Exploring ggplot2, part 1 To get a first feel for ggplot2, let’s try to run some basic ggplot2 commands. Together, they build a plot of the mtcars dataset that contains information about 32 cars from a 1973 Motor Trend magazine. This dataset is small, intuitive, and contains a variety of continuous and categorical variables.

# Load the ggplot2 package
library(ggplot2)
# Explore the mtcars data frame with str()
str(mtcars)
'data.frame':   32 obs. of  11 variables:
 $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
 $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
 $ disp: num  160 160 108 258 360 ...
 $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
 $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
 $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
 $ qsec: num  16.5 17 18.6 19.4 17 ...
 $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
 $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
 $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
 $ carb: num  4 4 1 1 2 1 4 2 2 4 ...
# Execute the following command
ggplot(mtcars, aes(x = cyl, y = mpg)) +
  geom_point()

Exploring ggplot2, part 2 The plot from the previous exercise wasn’t really satisfying. Although cyl (the number of cylinders) is categorical, it is classified as numeric in mtcars. You’ll have to explicitly tell ggplot2 that cyl is a categorical variable.

# Change the command below so that cyl is treated as factor
ggplot(mtcars, aes(x = factor(cyl), y = mpg)) +
  geom_point()

Exploring ggplot2, part 3 We’ll use several datasets throughout the courses to showcase the concepts discussed in the videos. In the previous exercises, you already got to know mtcars. Let’s dive a little deeper to explore the three main topics in this course: The data, aesthetics, and geom layers.

The mtcars dataset contains information about 32 cars from 1973 Motor Trend magazine. This dataset is small, intuitive, and contains a variety of continuous and categorical variables.

You’re encouraged to think about how the examples and concepts we discuss throughout these data viz courses apply to your own data-sets!

# A scatter plot has been made for you
ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point()

# Replace ___ with the correct column
ggplot(mtcars, aes(x = wt, y = mpg, color = disp)) +
  geom_point()

# Replace ___ with the correct column
ggplot(mtcars, aes(x = wt, y = mpg, size = disp)) +
  geom_point()

Exploring ggplot2, part 4 The diamonds data frame contains information on the prices and various metrics of 50,000 diamonds. Among the variables included are carat (a measurement of the size of the diamond) and price. For the next exercises, you’ll be using a subset of 1,000 diamonds.

Here you’ll use two common geom layer functions: geom_point() and geom_smooth(). We already saw in the earlier exercises how these are added using the + operator.

# Explore the diamonds data frame with str()
str(diamonds)
Classes 'tbl_df', 'tbl' and 'data.frame':   53940 obs. of  10 variables:
 $ carat  : num  0.23 0.21 0.23 0.29 0.31 0.24 0.24 0.26 0.22 0.23 ...
 $ cut    : Ord.factor w/ 5 levels "Fair"<"Good"<..: 5 4 2 4 2 3 3 3 1 3 ...
 $ color  : Ord.factor w/ 7 levels "D"<"E"<"F"<"G"<..: 2 2 2 6 7 7 6 5 2 5 ...
 $ clarity: Ord.factor w/ 8 levels "I1"<"SI2"<"SI1"<..: 2 3 5 4 2 6 7 3 4 5 ...
 $ depth  : num  61.5 59.8 56.9 62.4 63.3 62.8 62.3 61.9 65.1 59.4 ...
 $ table  : num  55 61 65 58 58 57 57 55 61 61 ...
 $ price  : int  326 326 327 334 335 336 336 337 337 338 ...
 $ x      : num  3.95 3.89 4.05 4.2 4.34 3.94 3.95 4.07 3.87 4 ...
 $ y      : num  3.98 3.84 4.07 4.23 4.35 3.96 3.98 4.11 3.78 4.05 ...
 $ z      : num  2.43 2.31 2.31 2.63 2.75 2.48 2.47 2.53 2.49 2.39 ...
# Add geom_point() with +
ggplot(diamonds, aes(x = carat, y = price)) +
  geom_point()

# Add geom_point() and geom_smooth() with +
ggplot(diamonds, aes(x = carat, y = price)) +
  geom_point() +
    geom_smooth()

Exploring ggplot2, part 5 The code for last plot of the previous exercise is available in the script on the right. It builds a scatter plot of the diamonds dataset, with carat on the x-axis and price on the y-axis. geom_smooth() is used to add a smooth line.

With this plot as a starting point, let’s explore some more possibilities of combining geoms.

# 1 - The plot you created in the previous exercise
ggplot(diamonds, aes(x = carat, y = price)) +
  geom_point() +
  geom_smooth()

# 2 - Copy the above command but show only the smooth line
ggplot(diamonds, aes(x = carat, y = price)) +
  geom_smooth()

# 3 - Copy the above command and assign the correct value to col in aes()
ggplot(diamonds, aes(x = carat, y = price, color = clarity)) +
  geom_smooth()

# 4 - Keep the color settings from previous command. Plot only the points with argument alpha.
ggplot(diamonds, aes(x = carat, y = price, color = clarity)) +
  geom_point(alpha = 0.4)

Understanding the grammar, part 1 Here you’ll explore some of the different grammatical elements. Throughout this course, you’ll discover how they can be combined in all sorts of ways to develop unique plots.

In the following instructions, you’ll start by creating a ggplot object from the diamonds dataset. Next, you’ll add layers onto this object to build beautiful & informative plots.

# Create the object containing the data and aes layers: dia_plot
dia_plot <- ggplot(diamonds, aes(x = carat, y = price))
# Add a geom layer with + and geom_point()
dia_plot + geom_point()

# Add the same geom layer, but with aes() inside
dia_plot + geom_point(aes(color = clarity))

Understanding the grammar, part 2 Continuing with the previous exercise, here you’ll explore mixing arguments and aesthetics in a single geometry.

You’re still working on the diamonds dataset.

# 1 - The dia_plot object has been created for you
dia_plot <- ggplot(diamonds, aes(x = carat, y = price))
# 2 - Expand dia_plot by adding geom_point() with alpha set to 0.2
dia_plot <- dia_plot + geom_point(alpha = 0.2)
# 3 - Plot dia_plot with additional geom_smooth() with se set to FALSE
dia_plot + geom_smooth(se = F)

# 4 - Copy the command from above and add aes() with the correct mapping to geom_smooth()
dia_plot + geom_smooth(aes(col = clarity), se = F)

base package and ggplot2, part 1 - plot These courses are about understanding data visualization in the context of the grammar of graphics. To gain a better appreciation of ggplot2 and to understand how it operates differently from base package, it’s useful to make some comparisons.

In the video, you already saw one example of how to make a (poor) multivariate plot in base package. In this series of exercises you’ll take a look at a better way using the equivalent version in ggplot2.

First, let’s focus on base package. You want to make a plot of mpg (miles per gallon) against wt (weight in thousands of pounds) in the mtcars data frame, but this time you want the dots colored according to the number of cylinders, cyl. How would you do that in base package? You can use a little trick to color the dots by specifying a factor variable as a color. This works because factors are just a special class of the integer type.

# Plot the correct variables of mtcars
plot(mtcars$wt, mtcars$mpg, col = mtcars$cyl)

# Change cyl inside mtcars to a factor
mtcars$fcyl <- as.factor(mtcars$cyl)
# Make the same plot as in the first instruction
plot(mtcars$wt, mtcars$mpg, col = mtcars$fcyl)

base package and ggplot2, part 2 - lm If you want to add a linear model to your plot, shown right, you can define it with lm() and then plot the resulting linear model with abline(). However, if you want a model for each subgroup, according to cylinders, then you have a couple of options.

You can subset your data, and then calculate the lm() and plot each subset separately. Alternatively, you can vectorize over the cyl variable using lapply() and combine this all in one step. This option is already prepared for you.

The code to the right contains a call to the function lapply(), which you might not have seen before. This function takes as input a vector and a function. Then lapply() applies the function it was given to each element of the vector and returns the results in a list. In this case, lapply() takes each element of mtcars\(cyl and calls the function defined in the second argument. This function takes a value of mtcars\)cyl and then subsets the data so that only rows with cyl == x are used. Then it fits a linear model to the filtered dataset and uses that model to add a line to the plot with the abline() function.

Now that you have an interesting plot, there is a very important aspect missing - the legend!

# Use lm() to calculate a linear model and save it as carModel
carModel <- lm(mpg ~ wt, data = mtcars)
# Basic plot
mtcars$cyl <- as.factor(mtcars$cyl)
plot(mtcars$wt, mtcars$mpg, col = mtcars$cyl)
# Call abline() with carModel as first argument and set lty to 2
abline(carModel, lty = 2)

# Plot each subset efficiently with lapply
# You don't have to edit this code
plot(mtcars$wt, mtcars$mpg, col = mtcars$cyl)
lapply(mtcars$cyl, function(x) {
  abline(lm(mpg ~ wt, mtcars, subset = (cyl == x)), col = x)
  })
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

[[4]]
NULL

[[5]]
NULL

[[6]]
NULL

[[7]]
NULL

[[8]]
NULL

[[9]]
NULL

[[10]]
NULL

[[11]]
NULL

[[12]]
NULL

[[13]]
NULL

[[14]]
NULL

[[15]]
NULL

[[16]]
NULL

[[17]]
NULL

[[18]]
NULL

[[19]]
NULL

[[20]]
NULL

[[21]]
NULL

[[22]]
NULL

[[23]]
NULL

[[24]]
NULL

[[25]]
NULL

[[26]]
NULL

[[27]]
NULL

[[28]]
NULL

[[29]]
NULL

[[30]]
NULL

[[31]]
NULL

[[32]]
NULL
# This code will draw the legend of the plot
# You don't have to edit this code
legend(x = 5, y = 33, legend = levels(mtcars$cyl),
       col = 1:3, pch = 1, bty = "n")

base package and ggplot2, part 3 In this exercise you’ll recreate the base package plot in ggplot2.

The code for base R plotting is given at the top. The first line of code already converts the cyl variable of mtcars to a factor.

# Convert cyl to factor (don't need to change)
mtcars$cyl <- as.factor(mtcars$cyl)
# Example from base R (don't need to change)
plot(mtcars$wt, mtcars$mpg, col = mtcars$cyl)
abline(lm(mpg ~ wt, data = mtcars), lty = 2)
lapply(mtcars$cyl, function(x) {
  abline(lm(mpg ~ wt, mtcars, subset = (cyl == x)), col = x)
  })
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

[[4]]
NULL

[[5]]
NULL

[[6]]
NULL

[[7]]
NULL

[[8]]
NULL

[[9]]
NULL

[[10]]
NULL

[[11]]
NULL

[[12]]
NULL

[[13]]
NULL

[[14]]
NULL

[[15]]
NULL

[[16]]
NULL

[[17]]
NULL

[[18]]
NULL

[[19]]
NULL

[[20]]
NULL

[[21]]
NULL

[[22]]
NULL

[[23]]
NULL

[[24]]
NULL

[[25]]
NULL

[[26]]
NULL

[[27]]
NULL

[[28]]
NULL

[[29]]
NULL

[[30]]
NULL

[[31]]
NULL

[[32]]
NULL
legend(x = 5, y = 33, legend = levels(mtcars$cyl),
       col = 1:3, pch = 1, bty = "n")

# Plot 1: add geom_point() to this command to create a scatter plot
ggplot(mtcars, aes(x = wt, y = mpg, col = cyl)) +
  geom_point()  # Fill in using instructions Plot 1

# Plot 2: include the lines of the linear models, per cyl
ggplot(mtcars, aes(x = wt, y = mpg, col = cyl)) +
  geom_point() + # Copy from Plot 1
  geom_smooth(method = "lm", se = F)   # Fill in using instructions Plot 2

# Plot 3: include a lm for the entire dataset in its whole
ggplot(mtcars, aes(x = wt, y = mpg, col = cyl)) +
  geom_point() + # Copy from Plot 1
  geom_smooth(method = "lm", se = F) +
  geom_smooth(aes(group = 1), method="lm", se=F,linetype=2)   # Fill in using instructions Plot 3

Variables to visuals, part 1b In the last exercise you saw how iris.tidy was used to make a specific plot. It’s important to know how to rearrange your data in this way so that your plotting functions become easier. In this exercise you’ll use functions from the tidyr package to convert iris to iris.tidy.

The resulting iris.tidy data should look as follows:

  Species  Part Measure Value
1  setosa Sepal  Length   5.1
2  setosa Sepal  Length   4.9
3  setosa Sepal  Length   4.7
4  setosa Sepal  Length   4.6
5  setosa Sepal  Length   5.0
6  setosa Sepal  Length   5.4
...

You can have a look at the iris dataset by typing head(iris) in the console.

head(iris)

Variables to visuals, part 1 So far you’ve seen four different forms of the iris dataset: iris, iris.wide, iris.wide2 and iris.tidy. Don’t let all these different forms confuse you! It’s exactly the same data, just rearranged so that your plotting functions become easier.

To see this in action, consider the plot in the graphics device at right. Which form of the dataset would be the most appropriate to use here?

# Consider the structure of iris, iris.wide and iris.tidy (in that order)
str(iris)
'data.frame':   150 obs. of  5 variables:
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
str(iris.wide)
'data.frame':   300 obs. of  4 variables:
 $ Species: Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Part   : chr  "Petal" "Petal" "Petal" "Petal" ...
 $ Length : num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Width  : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
str(iris.tidy)
'data.frame':   600 obs. of  4 variables:
 $ Species: Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Part   : chr  "Sepal" "Sepal" "Sepal" "Sepal" ...
 $ Measure: chr  "Length" "Length" "Length" "Length" ...
 $ Value  : num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
# Think about which dataset you would use to get the plot shown right
# Fill in the ___ to produce the plot given to the right
ggplot(iris.tidy, aes(x = Species, y = Value, col = Part)) +
  geom_jitter() +
  facet_grid(. ~ Measure)

# Load the tidyr package
library(tidyr)
# Fill in the ___ to produce to the correct iris.tidy dataset
iris.tidy <- iris %>%
  gather(key, Value, -Species) %>%
  separate(key, c("Part", "Measure"), "\\.")

Variables to visuals, part 2 Here you’ll take a look at another plot variant, shown at right. Which of your data frames would be used to produce this plot?

# The 3 data frames (iris, iris.wide and iris.tidy) are available in your environment
# Execute head() on iris, iris.wide and iris.tidy (in that order)
head(iris)
head(iris.wide)
head(iris.tidy)
# Think about which dataset you would use to get the plot shown right
# Fill in the ___ to produce the plot given to the right
ggplot(iris.wide, aes(x = Length, y = Width, color = Part)) +
  geom_jitter() +
  facet_grid(. ~ Species)

Variables to visuals, part 2b In the last exercise you saw how iris.wide was used to make a specific plot. You also saw previously how you can derive iris.tidy from iris. Now you’ll move on to produce iris.wide.

The head of the iris.wide should look like this in the end:

Species Part Length Width 1 setosa Petal 1.4 0.2 2 setosa Petal 1.4 0.2 3 setosa Petal 1.3 0.2 4 setosa Petal 1.5 0.2 5 setosa Petal 1.4 0.2 6 setosa Petal 1.7 0.4 … You can have a look at the iris dataset by typing head(iris) in the console.

# Add column with unique ids (don't need to change)
iris$Flower <- 1:nrow(iris)
# Fill in the ___ to produce to the correct iris.wide dataset
iris.wide <- iris %>%
  gather(key, value, -Species, -Flower) %>%
  separate(key, c("Part", "Measure"), "\\.") %>%
  spread(Measure, value)

All about aesthetics, part 1 In the video you saw 9 visible aesthetics. Let’s apply them to a categorical variable - the cylinders in mtcars, cyl.

(You’ll consider line type when you encounter line plots in the next chapter).

These are the aesthetics you can consider within aes() in this chapter: x, y, color, fill, size, alpha, labels and shape.

In the following exercise you can assume that the cyl column is categorical. It has already been transformed into a factor for you.

# 1 - Map mpg to x and cyl to y
ggplot(mtcars, aes(x = mpg, y = cyl)) +
  geom_point()

  
# 2 - Reverse: Map cyl to x and mpg to y
ggplot(mtcars, aes(x = cyl, y = mpg)) +
  geom_point()

# 3 - Map wt to x, mpg to y and cyl to col
ggplot(mtcars, aes(x = wt, y = mpg, color = cyl)) +
  geom_point()

# 4 - Change shape and size of the points in the above plot
ggplot(mtcars, aes(x = wt, y = mpg, color = cyl)) +
  geom_point(shape = 1, size = 4)

All about aesthetics, part 2 The color aesthetic typically changes the outside outline of an object and the fill aesthetic is typically the inside shading. However, as you saw in the last exercise, geom_point() is an exception. Here you use color, instead of fill for the inside of the point. But it’s a bit subtler than that.

Which shape to use? The default geom_point() uses shape = 19 (a solid circle with an outline the same colour as the inside). Good alternatives are shape = 1 (hollow) and shape = 16 (solid, no outline). These all use the col aesthetic (don’t forget to set alpha for solid points).

A really nice alternative is shape = 21 which allows you to use both fill for the inside and col for the outline! This is a great little trick for when you want to map two aesthetics to a dot.

What happens when you use the wrong aesthetic mapping? This is a very common mistake! The code from the previous exercise is in the editor. Using this as your starting point complete the instructions.

# am and cyl are factors, wt is numeric
class(mtcars$am)
[1] "numeric"
class(mtcars$cyl)
[1] "factor"
class(mtcars$wt)
[1] "numeric"
# From the previous exercise
ggplot(mtcars, aes(x = wt, y = mpg, col = cyl)) +
  geom_point(shape = 1, size = 4)

# 1 - Map cyl to fill
ggplot(mtcars, aes(x = wt, y = mpg, fill = cyl)) +
  geom_point(shape = 1, size = 4)

# 2 - Change shape and alpha of the points in the above plot
ggplot(mtcars, aes(x = wt, y = mpg, fill = cyl)) +
  geom_point(shape = 21, size = 4, alpha = 0.6)

# 3 - Map am to col in the above plot
ggplot(mtcars, aes(x = wt, y = mpg, fill = cyl, col=am)) +
  geom_point(shape = 21, size = 4, alpha = 0.6)

All about aesthetics, part 3 Now that you’ve got some practice with incrementally building up plots, you can try to do it from scratch! The mtcars dataset is pre-loaded in the workspace.

# Map cyl to size
ggplot(mtcars, aes(x=wt, y=mpg, size = cyl)) +
  geom_point()

# Map cyl to alpha
ggplot(mtcars, aes(x=wt, y=mpg, alpha=cyl)) +
  geom_point()

# Map cyl to shape 
ggplot(mtcars, aes(x=wt, y=mpg, shape=cyl)) +
  geom_point()

# Map cyl to label
ggplot(mtcars, aes(x=wt, y=mpg, label=cyl) )+
  geom_text()

All about attributes, part 1 In the video you saw that you can use all the aesthetics as attributes. Let’s see how this works with the aesthetics you used in the previous exercises: x, y, color, fill, size, alpha, label and shape.

This time you’ll use these arguments to set attributes of the plot, not aesthetics. However, there are some pitfalls you’ll have to watch out for: these attributes can overwrite the aesthetics of your plot!

A word about shapes: In the exercise “All about aesthetics, part 2”, you saw that shape = 21 results in a point that has a fill and an outline. Shapes in R can have a value from 1-25. Shapes 1-20 can only accept a color aesthetic, but shapes 21-25 have both a color and a fill aesthetic. See the pch argument in par() for further discussion.

A word about hexadecimal colours: Hexadecimal, literally “related to 16”, is a base-16 alphanumeric counting system. Individual values come from the ranges 0-9 and A-F. This means there are 256 possible two-digit values (i.e. 00 - FF). Hexadecimal colours use this system to specify a six-digit code for Red, Green and Blue values (“#RRGGBB”) of a colour (i.e. Pure blue: “#0000FF”, black: “#000000”, white: “#FFFFFF”). R can accept hex codes as valid colours.

# Define a hexadecimal color
my_color <- "#4ABEFF"
# 1 - First scatter plot, with col aesthetic:
ggplot(mtcars, aes(x = wt, y = mpg, color = cyl)) +
geom_point()

# 2 - Plot 1, but set col attributes in geom layer:
ggplot(mtcars, aes(x = wt, y = mpg, color = cyl)) +
  geom_point(color = my_color)

# 3 - Plot 2, with fill instead of col aesthetic, plut shape and size attributes in geom layer.
ggplot(mtcars, aes(x = wt, y = mpg, fill = cyl)) +
  geom_point(color = my_color, size = 10, shape = 23)

All about attributes, part 2 In the videos you saw that you can use all the aesthetics as attributes. Let’s see how this works with the aesthetics you used in the previous exercises: x, y, color, fill, size, alpha, label and shape.

In this exercise you will set all kinds of attributes of the points!

You will continue to work with mtcars.

# Expand to draw points with alpha 0.5
ggplot(mtcars, aes(x = wt, y = mpg, fill = cyl)) +
  geom_point(alpha = 0.5)

  
# Expand to draw points with shape 24 and color yellow
ggplot(mtcars, aes(x = wt, y = mpg, fill = cyl))  +
  geom_point(color = "yellow", shape = 24)

  
# Expand to draw text with label rownames(mtcars) and color red
ggplot(mtcars, aes(x = wt, y = mpg, fill = cyl)) +
  geom_text(label = rownames(mtcars), color = "red")

Going all out In this exercise, you will gradually add more aesthetics layers to the plot. You’re still working with the mtcars dataset, but this time you’re using more features of the cars. For completeness, here is a list of all the features of the observations in mtcars:

mpg – Miles/(US) gallon cyl – Number of cylinders disp – Displacement (cu.in.) hp – Gross horsepower drat – Rear axle ratio wt – Weight (lb/1000) qsec – 1/4 mile time vs – V/S engine. am – Transmission (0 = automatic, 1 = manual) gear – Number of forward gears carb – Number of carburetors Notice that adding more aesthetics to your plot is not always a good idea. Adding aesthetic mappings to a plot will increase its complexity, and thus decrease its readability.

# Map mpg onto x, qsec onto y and factor(cyl) onto col
ggplot(mtcars, aes(x = mpg, y = qsec, col = factor(cyl))) +
  geom_point()

# Add mapping: factor(am) onto shape
ggplot(mtcars, aes(x = mpg, y = qsec, col = factor(cyl), shape = factor(am))) +
  geom_point()

# Add mapping: (hp/wt) onto size
ggplot(mtcars, aes(x = mpg, y = qsec, col = factor(cyl), shape = factor(am), size = (hp/wt))) +
  geom_point()

Position You saw how jittering worked in the video, but bar plots suffer from their own issues of overplotting, as you’ll see here. Use the “stack”, “fill” and “dodge” positions to reproduce the plot in the viewer.

The ggplot2 base layers (data and aesthetics) have already been coded; they’re stored in a variable cyl.am. It looks like this:

cyl.am <- ggplot(mtcars, aes(x = factor(cyl), fill = factor(am)))

cyl.am <- ggplot(mtcars, aes(x = factor(cyl), fill = factor(am)))
# The base layer, cyl.am, is available for you
# Add geom (position = "stack" by default)
cyl.am + 
  geom_bar(position = "stack")

# Fill - show proportion
cyl.am + 
  geom_bar(position = "fill")  

# Dodging - principles of similarity and proximity
cyl.am +
  geom_bar(position = "dodge") 

# Clean up the axes with scale_ functions
val = c("#E41A1C", "#377EB8")
lab = c("Manual", "Automatic")
cyl.am +
  geom_bar(position = "dodge") +
  scale_x_discrete("Cylinders") + 
  scale_y_continuous("Number") +
  scale_fill_manual("Transmission", 
                    values = val,
                    labels = lab) 

Setting a dummy aesthetic In the last chapter you saw that all the visible aesthetics can serve as attributes and aesthetics, but I very conveniently left out x and y. That’s because although you can make univariate plots (such as histograms, which you’ll get to in the next chapter), a y-axis will always be provided, even if you didn’t ask for it.

In the base package you can make univariate plots with stripchart() (shown in the viewer) directly and it will take care of a fake y axis for us. Since this is univariate data, there is no real y axis.

You can get the same thing in ggplot2, but it’s a bit more cumbersome. The only reason you’d really want to do this is if you were making many plots and you wanted them to be in the same style, or you wanted to take advantage of an aesthetic mapping (e.g. colour).

# 1 - Create jittered plot of mtcars, mpg onto x, 0 onto y
ggplot(mtcars, aes(x = mpg, y = 0)) +
  geom_jitter()

# 2 - Add function to change y axis limits
ggplot(mtcars, aes(x = mpg, y = 0)) +
  geom_jitter() +
  scale_y_continuous(limits = c(-2,2))

Overplotting 1 - Point shape and transparency In the previous section you saw that there are lots of ways to use aesthetics. Perhaps too many, because although they are possible, they are not all recommended. Let’s take a look at what works and what doesn’t.

So far you’ve focused on scatter plots since they are intuitive, easily understood and very common. A major consideration in any scatter plot is dealing with overplotting. You’ll encounter this topic again in the geometries layer, but you can already make some adjustments here.

You’ll have to deal with overplotting when you have:

Large datasets, Imprecise data and so points are not clearly separated on your plot (you saw this in the video with the iris dataset), Interval data (i.e. data appears at fixed values), or Aligned data values on a single axis. One very common technique that I’d recommend to always use when you have solid shapes it to use alpha blending (i.e. adding transparency). An alternative is to use hollow shapes. These are adjustments to make before even worrying about positioning. This addresses the first point as above, which you’ll see again in the next exercise.

# Basic scatter plot: wt on x-axis and mpg on y-axis; map cyl to col
ggplot(mtcars, aes(x = wt, y = mpg, color = cyl )) +
  geom_point(size = 4)

# Hollow circles - an improvement
ggplot(mtcars, aes(x = wt, y = mpg, color = cyl)) +
  geom_point(size = 4, shape = 1)

# Add transparency - very nice
ggplot(mtcars, aes(x = wt, y = mpg, color = cyl)) +
  geom_point(size = 4, alpha = 0.6)

Overplotting 2 - alpha with large datasets In a previous exercise we defined four situations in which you’d have to adjust for overplotting. You’ll consider the last two here with the diamonds dataset:

Large datasets. Aligned data values on a single axis

# Scatter plot: carat (x), price (y), clarity (color)
ggplot(diamonds, aes(x = carat, y = price, color = clarity)) +
  geom_point()

# Adjust for overplotting
ggplot(diamonds, aes(x = carat, y = price, color = clarity)) +
  geom_point(alpha = 0.5)

# Scatter plot: clarity (x), carat (y), price (color)
ggplot(diamonds, aes(x = clarity, y = carat, color = price)) +
  geom_point(alpha = 0.5)

# Dot plot with jittering
ggplot(diamonds, aes(x = clarity, y = carat, color = price)) +
  geom_point(alpha = 0.5, position = "jitter")

Scatter plots and jittering (1) You already saw a few examples using geom_point() where the result was not a scatter plot. For example, in the plot shown in the viewer a continuous variable, wt, is mapped to the y aesthetic, and a categorical variable, cyl, is mapped to the x aesthetic. This also leads to over-plotting, since the points are arranged on a single x position. You previously dealt with overplotting by setting the position = jitter inside geom_point(). Let’s look at some other solutions here.

# Shown in the viewer:
ggplot(mtcars, aes(x = cyl, y = wt)) +
  geom_point()

# Solutions:
# 1 - With geom_jitter()
ggplot(mtcars, aes(x = cyl, y = wt)) +
  geom_jitter()

# 2 - Set width in geom_jitter()
ggplot(mtcars, aes(x = cyl, y = wt)) +
  geom_jitter(width = 0.1)

# 3 - Set position = position_jitter() in geom_point() ()
ggplot(mtcars, aes(x = cyl, y = wt)) +
  geom_point(posiiton = position_jitter(0.1))
Ignoring unknown parameters: posiiton

Histograms Histograms are one of the most common and intuitive ways of showing distributions. In this exercise you’ll use the mtcars data frame to explore typical variations of simple histograms. But first, some background:

The x axis/aesthetic: The documentation for geom_histogram() states the argument stat = “bin” as a default. Recall that histograms cut up a continuous variable into discrete bins - thats what the stat “bin” is doing. You always get 30 evenly-sized bins by default, which is specified with the default argument binwidth = range/30. This is a pretty good starting point if you don’t know anything about the variable being ploted and want to start exploring.

The y axis/aesthetic: geom_histogram() only requires one aesthetic: x. But there is clearly a y axis on your plot, so where does it come from? Actually, there is a variable mapped to the y aesthetic, it’s called ..count… When geom_histogram() executed the binning statistic (see above), it not only cut up the data into discrete bins, but it also counted how many values are in each bin. So there is an internal data frame where this information is stored. The .. calls the variable count from this internal data frame. This is what appears on the y aesthetic. But it gets better! The density has also been calculated. This is the proportional frequency of this bin in relation to the whole data set. You use ..density.. to access this information.

# 1 - Make a univariate histogram
ggplot(mtcars, aes(x = mpg)) +
  geom_histogram()

# 2 - Plot 1, plus set binwidth to 1 in the geom layer
ggplot(mtcars, aes(x = mpg)) +
  geom_histogram(binwidth = 1)

# 3 - Plot 2, plus MAP ..density.. to the y aesthetic (i.e. in a second aes() function)
ggplot(mtcars, aes(x = mpg)) +
  geom_histogram(aes(y = ..density..), binwidth = 1)

# 4 - plot 3, plus SET the fill attribute to "#377EB8"
ggplot(mtcars, aes(x = mpg)) +
  geom_histogram(aes(y = ..density..), binwidth = 1, fill = "#377EB8")

Position In the previous chapter you saw that there are lots of ways to position scatter plots. Likewise, the geom_bar() and geom_histogram() geoms also have a position argument, which you can use to specify how to draw the bars of the plot.

Three position arguments will be introduced here:

stack: place the bars on top of each other. Counts are used. This is the default position. fill: place the bars on top of each other, but this time use proportions. dodge: place the bars next to each other. Counts are used. In this exercise you’ll draw the total count of cars having a given number of cylinders (cyl), according to manual or automatic transmission type (am) - as shown in the viewer.

Since, in the built-in mtcars data set, cyl and am are integers, they have already been converted to factor variables for you.

# Draw a bar plot of cyl, filled according to am
ggplot(mtcars, aes(x = cyl, fill = am)) +
  geom_bar()

# Change the position argument to stack
ggplot(mtcars, aes(x = cyl, fill = am)) +
  geom_bar(position = "stack")

# Change the position argument to fill
ggplot(mtcars, aes(x = cyl, fill = am)) +
  geom_bar(position = "fill")

# Change the position argument to dodge
ggplot(mtcars, aes(x = cyl, fill = am)) +
  geom_bar(position = "dodge")

Overlapping bar plots So far you’ve seen three different positions for bar plots: stack (the default), dodge (preferred), and fill (to show proportions).

However, you can go one step further by adjusting the dodging, so that your bars partially overlap each other. For this example you’ll again use the mtcars dataset. Like last time cyl and am are already available as factors inside mtcars.

Instead of using position = “dodge” you’re going to use position_dodge(), like you did with position_jitter() in the Scatter plots and jittering (1) exercise. Here, you’ll save this as an object, posn_d, so that you can easily reuse it.

Remember, the reason you want to use position_dodge() (and position_jitter()) is to specify how much dodging (or jittering) you want.

# 1 - The last plot form the previous exercise
ggplot(mtcars, aes(x = cyl, fill = am)) +
  geom_bar(position = "dodge")

# 2 - Define posn_d with position_dodge()
posn_d <- position_dodge(width = 0.2)
# 3 - Change the position argument to posn_d
ggplot(mtcars, aes(x = cyl, fill = am)) +
  geom_bar(position = posn_d)

# 4 - Use posn_d as position and adjust alpha to 0.6
ggplot(mtcars, aes(x = cyl, fill = am)) +
  geom_bar(position = posn_d, alpha = 0.6)

Overlapping histograms Overlapping histograms pose similar problems to overlapping bar plots, but there is a unique solution here: a frequency polygon.

This is a geom specific to binned data that draws a line connecting the value of each bin. Like geom_histogram(), it takes a binwidth argument and by default stat = “bin” and position = “identity”.

# A basic histogram, add coloring defined by cyl
ggplot(mtcars, aes(mpg, fill = cyl)) +
  geom_histogram(binwidth = 1)

# Change position to identity
ggplot(mtcars, aes(mpg, fill = cyl)) +
  geom_histogram(binwidth = 1, position = "identity")

# Change geom to freqpoly (position is identity by default)
ggplot(mtcars, aes(mpg,col = cyl)) +
  
  geom_freqpoly(binwidth = 1, position = "identity")

Bar plots with color ramp, part 1 In this example of a bar plot, you’ll fill each segment according to an ordinal variable. The best way to do that is with a sequential color series.

You’ll be using the Vocab dataset from earlier. Since this is a much larger dataset with more categories, you’ll also compare it to a simpler dataset, mtcars. Both datasets are ordinal.

# Example of how to use a brewed color palette
ggplot(mtcars, aes(x = cyl, fill = am)) +
  geom_bar() +
  scale_fill_brewer(palette = "Set1")

Overlapping histograms (2) As a last example of bar plots, you’ll return to histograms (which you now see are just a special type of bar plot). You saw a nice trick in a previous exercise of how to slightly overlap bars, but now you’ll see how to overlap them completely. This would be nice for multiple histograms, as long as there are not too many different overlaps!

You’ll make a histogram using the mpg variable in the mtcars data frame.

# 1 - Basic histogram plot command
ggplot(mtcars, aes(mpg)) +
  geom_histogram(binwidth = 1)

# 2 - Plot 1, Expand aesthetics: am onto fill
ggplot(mtcars, aes(mpg, fill = am)) +
  geom_histogram(binwidth = 1)

# 3 - Plot 2, change position = "dodge"
ggplot(mtcars, aes(mpg, fill = am)) +
  geom_histogram(binwidth = 1, position = "dodge")

# 4 - Plot 3, change position = "fill"
ggplot(mtcars, aes(mpg, fill = am)) +
  geom_histogram(binwidth = 1, position = "fill")

# 5 - Plot 4, plus change position = "identity" and alpha = 0.4
ggplot(mtcars, aes(mpg, fill = am)) +
  geom_histogram(binwidth = 1, position = "identity", alpha = 0.4)

# 6 - Plot 5, plus change mapping: cyl onto fill
ggplot(mtcars, aes(mpg, fill = cyl)) +
  geom_histogram(binwidth = 1, position = "identity", alpha = 0.4)

Line plots In the video you saw how to make line plots using time series data. To explore this topic, you’ll use the economics data frame, which contains time series for unemployment and population statistics from the Federal Reserve Bank of St. Louis in the US. The data is contained in the ggplot2 package.

To begin with, you can look at how the median unemployment time and the unemployment rate (the number of unemployed people as a proportion of the population) change over time.

In the next exercises, you’ll explore to how add embellishments to the line plots, such as recession periods.

# Print out head of economics
head(economics)
# Plot unemploy as a function of date using a line plot
ggplot(economics, aes(x = date, y = unemploy)) +
  geom_line()

# Adjust plot to represent the fraction of total population that is unemployed
ggplot(economics, aes(x = date, y = unemploy/pop)) +
  geom_line()

Periods of recession By themselves, time series often contain enough valuable information, but you always want to maximize the number of variables you can show in a plot. This allows you (and your viewers) to begin making comparisons between those variables that would otherwise be difficult or impossible.

Here, you’ll add shaded regions to the background to indicate recession periods. How do unemployment rate and recession period interact with each other?

In addition to the economics dataset from before, you’ll also use the recess dataset for the periods of recession. The recess data frame contains 2 variables: the begin period of the recession and the end. It’s already available in your workspace.

# Basic line plot
ggplot(economics, aes(x = date, y = unemploy/pop)) +
  geom_line()

# Expand the following command with geom_rect() to draw the recess periods
ggplot(economics, aes(x = date, y = unemploy/pop)) +
  geom_rect(data = recess,
         aes(xmin = begin, xmax = end, ymin = -Inf, ymax = +Inf),
         inherit.aes = FALSE, fill = "red", alpha = 0.2) +
  geom_line()

Multiple time series, part 1 In the data chapter we discussed how the form of your data affects how you can plot it. Here, you’ll explore that topic in the context of multiple time series.

The dataset you’ll use contains the global capture rates of seven salmon species from 1950 - 2010.

In your workspace, the following dataset is available:

fish.species: Each variable (column) is a Salmon Species and each observation (row) is one Year. To get a multiple time series plot, however, both Year and Species should be in their own column. You need tidy data: one variable per column. Once you have that you can get the plot shown in the viewer by mapping Year to the x aesthetic and Species to the color aesthetic.

You’ll use the gather() function of the tidyr package, which is already loaded for you.

# Check the structure as a starting point
str(fish.species)
'data.frame':   61 obs. of  8 variables:
 $ Year    : int  1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 ...
 $ Pink    : int  100600 259000 132600 235900 123400 244400 203400 270119 200798 200085 ...
 $ Chum    : int  139300 155900 113800 99800 148700 143700 158480 125377 132407 113114 ...
 $ Sockeye : int  64100 51200 58200 66100 83800 72000 84800 69676 100520 62472 ...
 $ Coho    : int  30500 40900 33600 32400 38300 45100 40000 39900 39200 32865 ...
 $ Rainbow : int  0 100 100 100 100 100 100 100 100 100 ...
 $ Chinook : int  23200 25500 24900 25300 24500 27700 25300 21200 20900 20335 ...
 $ Atlantic: int  10800 9701 9800 8800 9600 7800 8100 9000 8801 8700 ...
# Use gather to go from fish.species to fish.tidy
fish.tidy <- gather(fish.species, Species, Capture, -Year)

Multiple time series, part 2 Now that you have tidy data, you’re ready to make your plot! The data frame fish.tidy is already available in the workspace, so you can start right away!

# Recreate the plot shown on the right
ggplot(fish.tidy, aes(x = Year, y = Capture, color = Species)) + geom_line()

Using qplot For simple exploratory plots, there are a variety of functions available. ggplot2 offers a powerful and diverse array of functions, but qplot() allows for quick and dirty plots. Plus, you should also be familiar with basic plotting notation.

# The old way (shown)
plot(mpg ~ wt, data = mtcars) # formula notation

with(mtcars, plot(wt, mpg)) # x, y notation

# Using ggplot:
ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point()

# Using qplot:
qplot(wt, mpg, data = mtcars)

Using aesthetics You already saw how some aesthetics are only applicable to categorical variables, such as shapes and linetypes. But just because others, such as size and color (and hence fill), can be applied to both categorical and continuous variables, doesn’t mean that they’re suitable for both.

# basic scatter plot:
qplot(wt, mpg, data = mtcars)

# Categorical:
# cyl
qplot(wt, mpg, data = mtcars, size = factor(cyl))

# gear
qplot(wt, mpg, data = mtcars, size = factor(gear))

# Continuous
# hp
qplot(wt, mpg, data = mtcars, color = hp)

# qsec
qplot(wt, mpg, data = mtcars, color = qsec)

Choosing geoms, part 1 qplot automatically takes care of assigning a geom to our plot given the type of data, but you can specify the geom yourselves.

# qplot() with x only
qplot(x = factor(cyl), data = mtcars)

# qplot() with x and y
qplot(x = factor(cyl), y = factor(vs), data = mtcars)

# qplot() with geom set to jitter manually
qplot(x = factor(cyl), y = factor(vs), data = mtcars, geom = "jitter")

Choosing geoms, part 2 - dotplot Some naming conventions:

Scatter plots: Continuous x, continuous y. Dot plots: Categorical x, continuous y. You use geom_point() for both plot types. Jittering position is set in the geom_point() layer.

However, to make a “true” dot plot, you can use geom_dotplot(). The difference is that unlike geom_point(), geom_dotplot() uses a binning statistic. Binning means to cut up a continuous variable (the y in this case) into discrete “bins”. You already saw binning with geom_histogram() (see this exercise for a refresher).

One thing to notice is that geom_dotplot() uses a different plotting symbol to geom_point(). For these symbols, the color aesthetic changes the color of its border, and the fill aesthetic changes the color of its interior.

Let’s take a look at how the two geoms compare.

# cyl and am are factors, wt is numeric
class(mtcars$cyl)
[1] "factor"
class(mtcars$am)
[1] "numeric"
class(mtcars$wt)
[1] "numeric"
# "Basic" dot plot, with geom_point():
ggplot(mtcars, aes(cyl, wt, col = am)) +
  geom_point(position = position_jitter(0.2, 0))

# 1 - "True" dot plot, with geom_dotplot():
ggplot(mtcars, aes(cyl, wt, fill = am)) +
  geom_dotplot(binaxis = "y", stackdir = "center")

# 2 - qplot with geom "dotplot", binaxis = "y" and stackdir = "center"
qplot(
  cyl, wt,
  data = mtcars,
  fill = am,
  geom = "dotplot",
  binaxis = "y",
  stackdir = "center"
)

Chicken weight The ChickWeight dataset is a data frame which represents the progression of weight of several chicks. The little chicklings are each given a specific diet. There are four types of diet and the farmer wants to know which one fattens the chicks the fastest.

It’s time to do some exploratory statistics on the data frame using the techniques you learned in this course! Let’s do some ggplot-ing!

# ChickWeight is available in your workspace
# 1 - Check out the head of ChickWeight
head(ChickWeight)
Grouped Data: weight ~ Time | Chick
  weight Time Chick Diet
1     42    0     1    1
2     51    2     1    1
3     59    4     1    1
4     64    6     1    1
5     76    8     1    1
6     93   10     1    1
# 2 - Basic line plot
ggplot(ChickWeight, aes(x = Time, y = weight)) +
  geom_line(aes(group = Chick))

# 3 - Take plot 2, map Diet onto col.
ggplot(ChickWeight, aes(x = Time, y = weight, color = Diet)) +
  geom_line(aes(group = Chick))

# 4 - Take plot 3, add geom_smooth()
ggplot(ChickWeight, aes(x = Time, y = weight, color = Diet)) +
  geom_line(aes(group = Chick), alpha = 0.3) +
  geom_smooth(lwd = 2, se = FALSE)

LS0tCnRpdGxlOiAiRGF0YSBWaXN1YWxpemF0aW9uIHdpdGggZ2dwbG90IDEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkV4cGxvcmluZyBnZ3Bsb3QyLCBwYXJ0IDEKVG8gZ2V0IGEgZmlyc3QgZmVlbCBmb3IgZ2dwbG90MiwgbGV0J3MgdHJ5IHRvIHJ1biBzb21lIGJhc2ljIGdncGxvdDIgY29tbWFuZHMuIFRvZ2V0aGVyLCB0aGV5IGJ1aWxkIGEgcGxvdCBvZiB0aGUgbXRjYXJzIGRhdGFzZXQgdGhhdCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCAzMiBjYXJzIGZyb20gYSAxOTczIE1vdG9yIFRyZW5kIG1hZ2F6aW5lLiBUaGlzIGRhdGFzZXQgaXMgc21hbGwsIGludHVpdGl2ZSwgYW5kIGNvbnRhaW5zIGEgdmFyaWV0eSBvZiBjb250aW51b3VzIGFuZCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuCgpgYGB7cn0KIyBMb2FkIHRoZSBnZ3Bsb3QyIHBhY2thZ2UKbGlicmFyeShnZ3Bsb3QyKQoKIyBFeHBsb3JlIHRoZSBtdGNhcnMgZGF0YSBmcmFtZSB3aXRoIHN0cigpCnN0cihtdGNhcnMpCgojIEV4ZWN1dGUgdGhlIGZvbGxvd2luZyBjb21tYW5kCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gY3lsLCB5ID0gbXBnKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCkV4cGxvcmluZyBnZ3Bsb3QyLCBwYXJ0IDIKVGhlIHBsb3QgZnJvbSB0aGUgcHJldmlvdXMgZXhlcmNpc2Ugd2Fzbid0IHJlYWxseSBzYXRpc2Z5aW5nLiBBbHRob3VnaCBjeWwgKHRoZSBudW1iZXIgb2YgY3lsaW5kZXJzKSBpcyBjYXRlZ29yaWNhbCwgaXQgaXMgY2xhc3NpZmllZCBhcyBudW1lcmljIGluIG10Y2Fycy4gWW91J2xsIGhhdmUgdG8gZXhwbGljaXRseSB0ZWxsIGdncGxvdDIgdGhhdCBjeWwgaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZS4KCmBgYHtyfQojIENoYW5nZSB0aGUgY29tbWFuZCBiZWxvdyBzbyB0aGF0IGN5bCBpcyB0cmVhdGVkIGFzIGZhY3RvcgpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGZhY3RvcihjeWwpLCB5ID0gbXBnKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCkV4cGxvcmluZyBnZ3Bsb3QyLCBwYXJ0IDMKV2UnbGwgdXNlIHNldmVyYWwgZGF0YXNldHMgdGhyb3VnaG91dCB0aGUgY291cnNlcyB0byBzaG93Y2FzZSB0aGUgY29uY2VwdHMgZGlzY3Vzc2VkIGluIHRoZSB2aWRlb3MuIEluIHRoZSBwcmV2aW91cyBleGVyY2lzZXMsIHlvdSBhbHJlYWR5IGdvdCB0byBrbm93IG10Y2Fycy4gTGV0J3MgZGl2ZSBhIGxpdHRsZSBkZWVwZXIgdG8gZXhwbG9yZSB0aGUgdGhyZWUgbWFpbiB0b3BpY3MgaW4gdGhpcyBjb3Vyc2U6IFRoZSBkYXRhLCBhZXN0aGV0aWNzLCBhbmQgZ2VvbSBsYXllcnMuCgpUaGUgbXRjYXJzIGRhdGFzZXQgY29udGFpbnMgaW5mb3JtYXRpb24gYWJvdXQgMzIgY2FycyBmcm9tIDE5NzMgTW90b3IgVHJlbmQgbWFnYXppbmUuIFRoaXMgZGF0YXNldCBpcyBzbWFsbCwgaW50dWl0aXZlLCBhbmQgY29udGFpbnMgYSB2YXJpZXR5IG9mIGNvbnRpbnVvdXMgYW5kIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4KCllvdSdyZSBlbmNvdXJhZ2VkIHRvIHRoaW5rIGFib3V0IGhvdyB0aGUgZXhhbXBsZXMgYW5kIGNvbmNlcHRzIHdlIGRpc2N1c3MgdGhyb3VnaG91dCB0aGVzZSBkYXRhIHZpeiBjb3Vyc2VzIGFwcGx5IHRvIHlvdXIgb3duIGRhdGEtc2V0cyEKCmBgYHtyfQojIEEgc2NhdHRlciBwbG90IGhhcyBiZWVuIG1hZGUgZm9yIHlvdQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnKSkgKwogIGdlb21fcG9pbnQoKQoKIyBSZXBsYWNlIF9fXyB3aXRoIHRoZSBjb3JyZWN0IGNvbHVtbgpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2xvciA9IGRpc3ApKSArCiAgZ2VvbV9wb2ludCgpCgojIFJlcGxhY2UgX19fIHdpdGggdGhlIGNvcnJlY3QgY29sdW1uCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIHNpemUgPSBkaXNwKSkgKwogIGdlb21fcG9pbnQoKQoKYGBgCgpFeHBsb3JpbmcgZ2dwbG90MiwgcGFydCA0ClRoZSBkaWFtb25kcyBkYXRhIGZyYW1lIGNvbnRhaW5zIGluZm9ybWF0aW9uIG9uIHRoZSBwcmljZXMgYW5kIHZhcmlvdXMgbWV0cmljcyBvZiA1MCwwMDAgZGlhbW9uZHMuIEFtb25nIHRoZSB2YXJpYWJsZXMgaW5jbHVkZWQgYXJlIGNhcmF0IChhIG1lYXN1cmVtZW50IG9mIHRoZSBzaXplIG9mIHRoZSBkaWFtb25kKSBhbmQgcHJpY2UuIEZvciB0aGUgbmV4dCBleGVyY2lzZXMsIHlvdSdsbCBiZSB1c2luZyBhIHN1YnNldCBvZiAxLDAwMCBkaWFtb25kcy4KCkhlcmUgeW91J2xsIHVzZSB0d28gY29tbW9uIGdlb20gbGF5ZXIgZnVuY3Rpb25zOiBnZW9tX3BvaW50KCkgYW5kIGdlb21fc21vb3RoKCkuIFdlIGFscmVhZHkgc2F3IGluIHRoZSBlYXJsaWVyIGV4ZXJjaXNlcyBob3cgdGhlc2UgYXJlIGFkZGVkIHVzaW5nIHRoZSArIG9wZXJhdG9yLgoKYGBge3J9CiMgRXhwbG9yZSB0aGUgZGlhbW9uZHMgZGF0YSBmcmFtZSB3aXRoIHN0cigpCnN0cihkaWFtb25kcykKCiMgQWRkIGdlb21fcG9pbnQoKSB3aXRoICsKZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGNhcmF0LCB5ID0gcHJpY2UpKSArCiAgZ2VvbV9wb2ludCgpCgoKIyBBZGQgZ2VvbV9wb2ludCgpIGFuZCBnZW9tX3Ntb290aCgpIHdpdGggKwpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpICsKICBnZW9tX3BvaW50KCkgKwogICAgZ2VvbV9zbW9vdGgoKQpgYGAKCkV4cGxvcmluZyBnZ3Bsb3QyLCBwYXJ0IDUKVGhlIGNvZGUgZm9yIGxhc3QgcGxvdCBvZiB0aGUgcHJldmlvdXMgZXhlcmNpc2UgaXMgYXZhaWxhYmxlIGluIHRoZSBzY3JpcHQgb24gdGhlIHJpZ2h0LiBJdCBidWlsZHMgYSBzY2F0dGVyIHBsb3Qgb2YgdGhlIGRpYW1vbmRzIGRhdGFzZXQsIHdpdGggY2FyYXQgb24gdGhlIHgtYXhpcyBhbmQgcHJpY2Ugb24gdGhlIHktYXhpcy4gZ2VvbV9zbW9vdGgoKSBpcyB1c2VkIHRvIGFkZCBhIHNtb290aCBsaW5lLgoKV2l0aCB0aGlzIHBsb3QgYXMgYSBzdGFydGluZyBwb2ludCwgbGV0J3MgZXhwbG9yZSBzb21lIG1vcmUgcG9zc2liaWxpdGllcyBvZiBjb21iaW5pbmcgZ2VvbXMuCgpgYGB7cn0KIyAxIC0gVGhlIHBsb3QgeW91IGNyZWF0ZWQgaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoKQoKIyAyIC0gQ29weSB0aGUgYWJvdmUgY29tbWFuZCBidXQgc2hvdyBvbmx5IHRoZSBzbW9vdGggbGluZQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpICsKICBnZW9tX3Ntb290aCgpCgoKIyAzIC0gQ29weSB0aGUgYWJvdmUgY29tbWFuZCBhbmQgYXNzaWduIHRoZSBjb3JyZWN0IHZhbHVlIHRvIGNvbCBpbiBhZXMoKQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSwgY29sb3IgPSBjbGFyaXR5KSkgKwogIGdlb21fc21vb3RoKCkKCgojIDQgLSBLZWVwIHRoZSBjb2xvciBzZXR0aW5ncyBmcm9tIHByZXZpb3VzIGNvbW1hbmQuIFBsb3Qgb25seSB0aGUgcG9pbnRzIHdpdGggYXJndW1lbnQgYWxwaGEuCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlLCBjb2xvciA9IGNsYXJpdHkpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNCkKYGBgCgpVbmRlcnN0YW5kaW5nIHRoZSBncmFtbWFyLCBwYXJ0IDEKSGVyZSB5b3UnbGwgZXhwbG9yZSBzb21lIG9mIHRoZSBkaWZmZXJlbnQgZ3JhbW1hdGljYWwgZWxlbWVudHMuIFRocm91Z2hvdXQgdGhpcyBjb3Vyc2UsIHlvdSdsbCBkaXNjb3ZlciBob3cgdGhleSBjYW4gYmUgY29tYmluZWQgaW4gYWxsIHNvcnRzIG9mIHdheXMgdG8gZGV2ZWxvcCB1bmlxdWUgcGxvdHMuCgpJbiB0aGUgZm9sbG93aW5nIGluc3RydWN0aW9ucywgeW91J2xsIHN0YXJ0IGJ5IGNyZWF0aW5nIGEgZ2dwbG90IG9iamVjdCBmcm9tIHRoZSBkaWFtb25kcyBkYXRhc2V0LiBOZXh0LCB5b3UnbGwgYWRkIGxheWVycyBvbnRvIHRoaXMgb2JqZWN0IHRvIGJ1aWxkIGJlYXV0aWZ1bCAmIGluZm9ybWF0aXZlIHBsb3RzLgoKYGBge3J9CiMgQ3JlYXRlIHRoZSBvYmplY3QgY29udGFpbmluZyB0aGUgZGF0YSBhbmQgYWVzIGxheWVyczogZGlhX3Bsb3QKZGlhX3Bsb3QgPC0gZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGNhcmF0LCB5ID0gcHJpY2UpKQoKIyBBZGQgYSBnZW9tIGxheWVyIHdpdGggKyBhbmQgZ2VvbV9wb2ludCgpCmRpYV9wbG90ICsgZ2VvbV9wb2ludCgpCgojIEFkZCB0aGUgc2FtZSBnZW9tIGxheWVyLCBidXQgd2l0aCBhZXMoKSBpbnNpZGUKZGlhX3Bsb3QgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNsYXJpdHkpKQpgYGAKClVuZGVyc3RhbmRpbmcgdGhlIGdyYW1tYXIsIHBhcnQgMgpDb250aW51aW5nIHdpdGggdGhlIHByZXZpb3VzIGV4ZXJjaXNlLCBoZXJlIHlvdSdsbCBleHBsb3JlIG1peGluZyBhcmd1bWVudHMgYW5kIGFlc3RoZXRpY3MgaW4gYSBzaW5nbGUgZ2VvbWV0cnkuCgpZb3UncmUgc3RpbGwgd29ya2luZyBvbiB0aGUgZGlhbW9uZHMgZGF0YXNldC4KCmBgYHtyfQojIDEgLSBUaGUgZGlhX3Bsb3Qgb2JqZWN0IGhhcyBiZWVuIGNyZWF0ZWQgZm9yIHlvdQpkaWFfcGxvdCA8LSBnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpCgojIDIgLSBFeHBhbmQgZGlhX3Bsb3QgYnkgYWRkaW5nIGdlb21fcG9pbnQoKSB3aXRoIGFscGhhIHNldCB0byAwLjIKZGlhX3Bsb3QgPC0gZGlhX3Bsb3QgKyBnZW9tX3BvaW50KGFscGhhID0gMC4yKQoKIyAzIC0gUGxvdCBkaWFfcGxvdCB3aXRoIGFkZGl0aW9uYWwgZ2VvbV9zbW9vdGgoKSB3aXRoIHNlIHNldCB0byBGQUxTRQpkaWFfcGxvdCArIGdlb21fc21vb3RoKHNlID0gRikKCiMgNCAtIENvcHkgdGhlIGNvbW1hbmQgZnJvbSBhYm92ZSBhbmQgYWRkIGFlcygpIHdpdGggdGhlIGNvcnJlY3QgbWFwcGluZyB0byBnZW9tX3Ntb290aCgpCmRpYV9wbG90ICsgZ2VvbV9zbW9vdGgoYWVzKGNvbCA9IGNsYXJpdHkpLCBzZSA9IEYpCgpgYGAKCmJhc2UgcGFja2FnZSBhbmQgZ2dwbG90MiwgcGFydCAxIC0gcGxvdApUaGVzZSBjb3Vyc2VzIGFyZSBhYm91dCB1bmRlcnN0YW5kaW5nIGRhdGEgdmlzdWFsaXphdGlvbiBpbiB0aGUgY29udGV4dCBvZiB0aGUgZ3JhbW1hciBvZiBncmFwaGljcy4gVG8gZ2FpbiBhIGJldHRlciBhcHByZWNpYXRpb24gb2YgZ2dwbG90MiBhbmQgdG8gdW5kZXJzdGFuZCBob3cgaXQgb3BlcmF0ZXMgZGlmZmVyZW50bHkgZnJvbSBiYXNlIHBhY2thZ2UsIGl0J3MgdXNlZnVsIHRvIG1ha2Ugc29tZSBjb21wYXJpc29ucy4KCkluIHRoZSB2aWRlbywgeW91IGFscmVhZHkgc2F3IG9uZSBleGFtcGxlIG9mIGhvdyB0byBtYWtlIGEgKHBvb3IpIG11bHRpdmFyaWF0ZSBwbG90IGluIGJhc2UgcGFja2FnZS4gSW4gdGhpcyBzZXJpZXMgb2YgZXhlcmNpc2VzIHlvdSdsbCB0YWtlIGEgbG9vayBhdCBhIGJldHRlciB3YXkgdXNpbmcgdGhlIGVxdWl2YWxlbnQgdmVyc2lvbiBpbiBnZ3Bsb3QyLgoKRmlyc3QsIGxldCdzIGZvY3VzIG9uIGJhc2UgcGFja2FnZS4gWW91IHdhbnQgdG8gbWFrZSBhIHBsb3Qgb2YgbXBnIChtaWxlcyBwZXIgZ2FsbG9uKSBhZ2FpbnN0IHd0ICh3ZWlnaHQgaW4gdGhvdXNhbmRzIG9mIHBvdW5kcykgaW4gdGhlIG10Y2FycyBkYXRhIGZyYW1lLCBidXQgdGhpcyB0aW1lIHlvdSB3YW50IHRoZSBkb3RzIGNvbG9yZWQgYWNjb3JkaW5nIHRvIHRoZSBudW1iZXIgb2YgY3lsaW5kZXJzLCBjeWwuIEhvdyB3b3VsZCB5b3UgZG8gdGhhdCBpbiBiYXNlIHBhY2thZ2U/IFlvdSBjYW4gdXNlIGEgbGl0dGxlIHRyaWNrIHRvIGNvbG9yIHRoZSBkb3RzIGJ5IHNwZWNpZnlpbmcgYSBmYWN0b3IgdmFyaWFibGUgYXMgYSBjb2xvci4gVGhpcyB3b3JrcyBiZWNhdXNlIGZhY3RvcnMgYXJlIGp1c3QgYSBzcGVjaWFsIGNsYXNzIG9mIHRoZSBpbnRlZ2VyIHR5cGUuCgpgYGB7cn0KIyBQbG90IHRoZSBjb3JyZWN0IHZhcmlhYmxlcyBvZiBtdGNhcnMKcGxvdChtdGNhcnMkd3QsIG10Y2FycyRtcGcsIGNvbCA9IG10Y2FycyRjeWwpCgojIENoYW5nZSBjeWwgaW5zaWRlIG10Y2FycyB0byBhIGZhY3RvcgptdGNhcnMkZmN5bCA8LSBhcy5mYWN0b3IobXRjYXJzJGN5bCkKCiMgTWFrZSB0aGUgc2FtZSBwbG90IGFzIGluIHRoZSBmaXJzdCBpbnN0cnVjdGlvbgpwbG90KG10Y2FycyR3dCwgbXRjYXJzJG1wZywgY29sID0gbXRjYXJzJGZjeWwpCmBgYAoKYmFzZSBwYWNrYWdlIGFuZCBnZ3Bsb3QyLCBwYXJ0IDIgLSBsbQpJZiB5b3Ugd2FudCB0byBhZGQgYSBsaW5lYXIgbW9kZWwgdG8geW91ciBwbG90LCBzaG93biByaWdodCwgeW91IGNhbiBkZWZpbmUgaXQgd2l0aCBsbSgpIGFuZCB0aGVuIHBsb3QgdGhlIHJlc3VsdGluZyBsaW5lYXIgbW9kZWwgd2l0aCBhYmxpbmUoKS4gSG93ZXZlciwgaWYgeW91IHdhbnQgYSBtb2RlbCBmb3IgZWFjaCBzdWJncm91cCwgYWNjb3JkaW5nIHRvIGN5bGluZGVycywgdGhlbiB5b3UgaGF2ZSBhIGNvdXBsZSBvZiBvcHRpb25zLgoKWW91IGNhbiBzdWJzZXQgeW91ciBkYXRhLCBhbmQgdGhlbiBjYWxjdWxhdGUgdGhlIGxtKCkgYW5kIHBsb3QgZWFjaCBzdWJzZXQgc2VwYXJhdGVseS4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiB2ZWN0b3JpemUgb3ZlciB0aGUgY3lsIHZhcmlhYmxlIHVzaW5nIGxhcHBseSgpIGFuZCBjb21iaW5lIHRoaXMgYWxsIGluIG9uZSBzdGVwLiBUaGlzIG9wdGlvbiBpcyBhbHJlYWR5IHByZXBhcmVkIGZvciB5b3UuCgpUaGUgY29kZSB0byB0aGUgcmlnaHQgY29udGFpbnMgYSBjYWxsIHRvIHRoZSBmdW5jdGlvbiBsYXBwbHkoKSwgd2hpY2ggeW91IG1pZ2h0IG5vdCBoYXZlIHNlZW4gYmVmb3JlLiBUaGlzIGZ1bmN0aW9uIHRha2VzIGFzIGlucHV0IGEgdmVjdG9yIGFuZCBhIGZ1bmN0aW9uLiBUaGVuIGxhcHBseSgpIGFwcGxpZXMgdGhlIGZ1bmN0aW9uIGl0IHdhcyBnaXZlbiB0byBlYWNoIGVsZW1lbnQgb2YgdGhlIHZlY3RvciBhbmQgcmV0dXJucyB0aGUgcmVzdWx0cyBpbiBhIGxpc3QuIEluIHRoaXMgY2FzZSwgbGFwcGx5KCkgdGFrZXMgZWFjaCBlbGVtZW50IG9mIG10Y2FycyRjeWwgYW5kIGNhbGxzIHRoZSBmdW5jdGlvbiBkZWZpbmVkIGluIHRoZSBzZWNvbmQgYXJndW1lbnQuIFRoaXMgZnVuY3Rpb24gdGFrZXMgYSB2YWx1ZSBvZiBtdGNhcnMkY3lsIGFuZCB0aGVuIHN1YnNldHMgdGhlIGRhdGEgc28gdGhhdCBvbmx5IHJvd3Mgd2l0aCBjeWwgPT0geCBhcmUgdXNlZC4gVGhlbiBpdCBmaXRzIGEgbGluZWFyIG1vZGVsIHRvIHRoZSBmaWx0ZXJlZCBkYXRhc2V0IGFuZCB1c2VzIHRoYXQgbW9kZWwgdG8gYWRkIGEgbGluZSB0byB0aGUgcGxvdCB3aXRoIHRoZSBhYmxpbmUoKSBmdW5jdGlvbi4KCk5vdyB0aGF0IHlvdSBoYXZlIGFuIGludGVyZXN0aW5nIHBsb3QsIHRoZXJlIGlzIGEgdmVyeSBpbXBvcnRhbnQgYXNwZWN0IG1pc3NpbmcgLSB0aGUgbGVnZW5kIQoKYGBge3J9CiMgVXNlIGxtKCkgdG8gY2FsY3VsYXRlIGEgbGluZWFyIG1vZGVsIGFuZCBzYXZlIGl0IGFzIGNhck1vZGVsCmNhck1vZGVsIDwtIGxtKG1wZyB+IHd0LCBkYXRhID0gbXRjYXJzKQoKIyBCYXNpYyBwbG90Cm10Y2FycyRjeWwgPC0gYXMuZmFjdG9yKG10Y2FycyRjeWwpCnBsb3QobXRjYXJzJHd0LCBtdGNhcnMkbXBnLCBjb2wgPSBtdGNhcnMkY3lsKQoKIyBDYWxsIGFibGluZSgpIHdpdGggY2FyTW9kZWwgYXMgZmlyc3QgYXJndW1lbnQgYW5kIHNldCBsdHkgdG8gMgphYmxpbmUoY2FyTW9kZWwsIGx0eSA9IDIpCgojIFBsb3QgZWFjaCBzdWJzZXQgZWZmaWNpZW50bHkgd2l0aCBsYXBwbHkKIyBZb3UgZG9uJ3QgaGF2ZSB0byBlZGl0IHRoaXMgY29kZQpwbG90KG10Y2FycyR3dCwgbXRjYXJzJG1wZywgY29sID0gbXRjYXJzJGN5bCkKbGFwcGx5KG10Y2FycyRjeWwsIGZ1bmN0aW9uKHgpIHsKICBhYmxpbmUobG0obXBnIH4gd3QsIG10Y2Fycywgc3Vic2V0ID0gKGN5bCA9PSB4KSksIGNvbCA9IHgpCiAgfSkKCiMgVGhpcyBjb2RlIHdpbGwgZHJhdyB0aGUgbGVnZW5kIG9mIHRoZSBwbG90CiMgWW91IGRvbid0IGhhdmUgdG8gZWRpdCB0aGlzIGNvZGUKbGVnZW5kKHggPSA1LCB5ID0gMzMsIGxlZ2VuZCA9IGxldmVscyhtdGNhcnMkY3lsKSwKICAgICAgIGNvbCA9IDE6MywgcGNoID0gMSwgYnR5ID0gIm4iKQpgYGAKCmJhc2UgcGFja2FnZSBhbmQgZ2dwbG90MiwgcGFydCAzCkluIHRoaXMgZXhlcmNpc2UgeW91J2xsIHJlY3JlYXRlIHRoZSBiYXNlIHBhY2thZ2UgcGxvdCBpbiBnZ3Bsb3QyLgoKVGhlIGNvZGUgZm9yIGJhc2UgUiBwbG90dGluZyBpcyBnaXZlbiBhdCB0aGUgdG9wLiBUaGUgZmlyc3QgbGluZSBvZiBjb2RlIGFscmVhZHkgY29udmVydHMgdGhlIGN5bCB2YXJpYWJsZSBvZiBtdGNhcnMgdG8gYSBmYWN0b3IuCgpgYGB7cn0KIyBDb252ZXJ0IGN5bCB0byBmYWN0b3IgKGRvbid0IG5lZWQgdG8gY2hhbmdlKQptdGNhcnMkY3lsIDwtIGFzLmZhY3RvcihtdGNhcnMkY3lsKQoKIyBFeGFtcGxlIGZyb20gYmFzZSBSIChkb24ndCBuZWVkIHRvIGNoYW5nZSkKcGxvdChtdGNhcnMkd3QsIG10Y2FycyRtcGcsIGNvbCA9IG10Y2FycyRjeWwpCmFibGluZShsbShtcGcgfiB3dCwgZGF0YSA9IG10Y2FycyksIGx0eSA9IDIpCmxhcHBseShtdGNhcnMkY3lsLCBmdW5jdGlvbih4KSB7CiAgYWJsaW5lKGxtKG1wZyB+IHd0LCBtdGNhcnMsIHN1YnNldCA9IChjeWwgPT0geCkpLCBjb2wgPSB4KQogIH0pCmxlZ2VuZCh4ID0gNSwgeSA9IDMzLCBsZWdlbmQgPSBsZXZlbHMobXRjYXJzJGN5bCksCiAgICAgICBjb2wgPSAxOjMsIHBjaCA9IDEsIGJ0eSA9ICJuIikKCiMgUGxvdCAxOiBhZGQgZ2VvbV9wb2ludCgpIHRvIHRoaXMgY29tbWFuZCB0byBjcmVhdGUgYSBzY2F0dGVyIHBsb3QKZ2dwbG90KG10Y2FycywgYWVzKHggPSB3dCwgeSA9IG1wZywgY29sID0gY3lsKSkgKwogIGdlb21fcG9pbnQoKSAgIyBGaWxsIGluIHVzaW5nIGluc3RydWN0aW9ucyBQbG90IDEKCiMgUGxvdCAyOiBpbmNsdWRlIHRoZSBsaW5lcyBvZiB0aGUgbGluZWFyIG1vZGVscywgcGVyIGN5bApnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2wgPSBjeWwpKSArCiAgZ2VvbV9wb2ludCgpICsgIyBDb3B5IGZyb20gUGxvdCAxCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGKSAgICMgRmlsbCBpbiB1c2luZyBpbnN0cnVjdGlvbnMgUGxvdCAyCgojIFBsb3QgMzogaW5jbHVkZSBhIGxtIGZvciB0aGUgZW50aXJlIGRhdGFzZXQgaW4gaXRzIHdob2xlCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGNvbCA9IGN5bCkpICsKICBnZW9tX3BvaW50KCkgKyAjIENvcHkgZnJvbSBQbG90IDEKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEYpICsKICBnZW9tX3Ntb290aChhZXMoZ3JvdXAgPSAxKSwgbWV0aG9kPSJsbSIsIHNlPUYsbGluZXR5cGU9MikgICAjIEZpbGwgaW4gdXNpbmcgaW5zdHJ1Y3Rpb25zIFBsb3QgMwpgYGAKClZhcmlhYmxlcyB0byB2aXN1YWxzLCBwYXJ0IDFiCkluIHRoZSBsYXN0IGV4ZXJjaXNlIHlvdSBzYXcgaG93IGlyaXMudGlkeSB3YXMgdXNlZCB0byBtYWtlIGEgc3BlY2lmaWMgcGxvdC4gSXQncyBpbXBvcnRhbnQgdG8ga25vdyBob3cgdG8gcmVhcnJhbmdlIHlvdXIgZGF0YSBpbiB0aGlzIHdheSBzbyB0aGF0IHlvdXIgcGxvdHRpbmcgZnVuY3Rpb25zIGJlY29tZSBlYXNpZXIuIEluIHRoaXMgZXhlcmNpc2UgeW91J2xsIHVzZSBmdW5jdGlvbnMgZnJvbSB0aGUgdGlkeXIgcGFja2FnZSB0byBjb252ZXJ0IGlyaXMgdG8gaXJpcy50aWR5LgoKVGhlIHJlc3VsdGluZyBpcmlzLnRpZHkgZGF0YSBzaG91bGQgbG9vayBhcyBmb2xsb3dzOgoKICAgICAgU3BlY2llcyAgUGFydCBNZWFzdXJlIFZhbHVlCiAgICAxICBzZXRvc2EgU2VwYWwgIExlbmd0aCAgIDUuMQogICAgMiAgc2V0b3NhIFNlcGFsICBMZW5ndGggICA0LjkKICAgIDMgIHNldG9zYSBTZXBhbCAgTGVuZ3RoICAgNC43CiAgICA0ICBzZXRvc2EgU2VwYWwgIExlbmd0aCAgIDQuNgogICAgNSAgc2V0b3NhIFNlcGFsICBMZW5ndGggICA1LjAKICAgIDYgIHNldG9zYSBTZXBhbCAgTGVuZ3RoICAgNS40CiAgICAuLi4KWW91IGNhbiBoYXZlIGEgbG9vayBhdCB0aGUgaXJpcyBkYXRhc2V0IGJ5IHR5cGluZyBoZWFkKGlyaXMpIGluIHRoZSBjb25zb2xlLgoKYGBge3J9CmhlYWQoaXJpcykKYGBgCgpWYXJpYWJsZXMgdG8gdmlzdWFscywgcGFydCAxClNvIGZhciB5b3UndmUgc2VlbiBmb3VyIGRpZmZlcmVudCBmb3JtcyBvZiB0aGUgaXJpcyBkYXRhc2V0OiBpcmlzLCBpcmlzLndpZGUsIGlyaXMud2lkZTIgYW5kIGlyaXMudGlkeS4gRG9uJ3QgbGV0IGFsbCB0aGVzZSBkaWZmZXJlbnQgZm9ybXMgY29uZnVzZSB5b3UhIEl0J3MgZXhhY3RseSB0aGUgc2FtZSBkYXRhLCBqdXN0IHJlYXJyYW5nZWQgc28gdGhhdCB5b3VyIHBsb3R0aW5nIGZ1bmN0aW9ucyBiZWNvbWUgZWFzaWVyLgoKVG8gc2VlIHRoaXMgaW4gYWN0aW9uLCBjb25zaWRlciB0aGUgcGxvdCBpbiB0aGUgZ3JhcGhpY3MgZGV2aWNlIGF0IHJpZ2h0LiBXaGljaCBmb3JtIG9mIHRoZSBkYXRhc2V0IHdvdWxkIGJlIHRoZSBtb3N0IGFwcHJvcHJpYXRlIHRvIHVzZSBoZXJlPwoKYGBge3J9CiMgQ29uc2lkZXIgdGhlIHN0cnVjdHVyZSBvZiBpcmlzLCBpcmlzLndpZGUgYW5kIGlyaXMudGlkeSAoaW4gdGhhdCBvcmRlcikKc3RyKGlyaXMpCnN0cihpcmlzLndpZGUpCnN0cihpcmlzLnRpZHkpCgojIFRoaW5rIGFib3V0IHdoaWNoIGRhdGFzZXQgeW91IHdvdWxkIHVzZSB0byBnZXQgdGhlIHBsb3Qgc2hvd24gcmlnaHQKIyBGaWxsIGluIHRoZSBfX18gdG8gcHJvZHVjZSB0aGUgcGxvdCBnaXZlbiB0byB0aGUgcmlnaHQKZ2dwbG90KGlyaXMudGlkeSwgYWVzKHggPSBTcGVjaWVzLCB5ID0gVmFsdWUsIGNvbCA9IFBhcnQpKSArCiAgZ2VvbV9qaXR0ZXIoKSArCiAgZmFjZXRfZ3JpZCguIH4gTWVhc3VyZSkKYGBgCgpgYGB7cn0KIyBMb2FkIHRoZSB0aWR5ciBwYWNrYWdlCmxpYnJhcnkodGlkeXIpCgojIEZpbGwgaW4gdGhlIF9fXyB0byBwcm9kdWNlIHRvIHRoZSBjb3JyZWN0IGlyaXMudGlkeSBkYXRhc2V0CmlyaXMudGlkeSA8LSBpcmlzICU+JQogIGdhdGhlcihrZXksIFZhbHVlLCAtU3BlY2llcykgJT4lCiAgc2VwYXJhdGUoa2V5LCBjKCJQYXJ0IiwgIk1lYXN1cmUiKSwgIlxcLiIpCmBgYAoKVmFyaWFibGVzIHRvIHZpc3VhbHMsIHBhcnQgMgpIZXJlIHlvdSdsbCB0YWtlIGEgbG9vayBhdCBhbm90aGVyIHBsb3QgdmFyaWFudCwgc2hvd24gYXQgcmlnaHQuIFdoaWNoIG9mIHlvdXIgZGF0YSBmcmFtZXMgd291bGQgYmUgdXNlZCB0byBwcm9kdWNlIHRoaXMgcGxvdD8KCmBgYHtyfQojIFRoZSAzIGRhdGEgZnJhbWVzIChpcmlzLCBpcmlzLndpZGUgYW5kIGlyaXMudGlkeSkgYXJlIGF2YWlsYWJsZSBpbiB5b3VyIGVudmlyb25tZW50CiMgRXhlY3V0ZSBoZWFkKCkgb24gaXJpcywgaXJpcy53aWRlIGFuZCBpcmlzLnRpZHkgKGluIHRoYXQgb3JkZXIpCmhlYWQoaXJpcykKaGVhZChpcmlzLndpZGUpCmhlYWQoaXJpcy50aWR5KQoKIyBUaGluayBhYm91dCB3aGljaCBkYXRhc2V0IHlvdSB3b3VsZCB1c2UgdG8gZ2V0IHRoZSBwbG90IHNob3duIHJpZ2h0CiMgRmlsbCBpbiB0aGUgX19fIHRvIHByb2R1Y2UgdGhlIHBsb3QgZ2l2ZW4gdG8gdGhlIHJpZ2h0CmdncGxvdChpcmlzLndpZGUsIGFlcyh4ID0gTGVuZ3RoLCB5ID0gV2lkdGgsIGNvbG9yID0gUGFydCkpICsKICBnZW9tX2ppdHRlcigpICsKICBmYWNldF9ncmlkKC4gfiBTcGVjaWVzKQpgYGAKClZhcmlhYmxlcyB0byB2aXN1YWxzLCBwYXJ0IDJiCkluIHRoZSBsYXN0IGV4ZXJjaXNlIHlvdSBzYXcgaG93IGlyaXMud2lkZSB3YXMgdXNlZCB0byBtYWtlIGEgc3BlY2lmaWMgcGxvdC4gWW91IGFsc28gc2F3IHByZXZpb3VzbHkgaG93IHlvdSBjYW4gZGVyaXZlIGlyaXMudGlkeSBmcm9tIGlyaXMuIE5vdyB5b3UnbGwgbW92ZSBvbiB0byBwcm9kdWNlIGlyaXMud2lkZS4KClRoZSBoZWFkIG9mIHRoZSBpcmlzLndpZGUgc2hvdWxkIGxvb2sgbGlrZSB0aGlzIGluIHRoZSBlbmQ6CgogIFNwZWNpZXMgIFBhcnQgTGVuZ3RoIFdpZHRoCjEgIHNldG9zYSBQZXRhbCAgICAxLjQgICAwLjIKMiAgc2V0b3NhIFBldGFsICAgIDEuNCAgIDAuMgozICBzZXRvc2EgUGV0YWwgICAgMS4zICAgMC4yCjQgIHNldG9zYSBQZXRhbCAgICAxLjUgICAwLjIKNSAgc2V0b3NhIFBldGFsICAgIDEuNCAgIDAuMgo2ICBzZXRvc2EgUGV0YWwgICAgMS43ICAgMC40Ci4uLgpZb3UgY2FuIGhhdmUgYSBsb29rIGF0IHRoZSBpcmlzIGRhdGFzZXQgYnkgdHlwaW5nIGhlYWQoaXJpcykgaW4gdGhlIGNvbnNvbGUuCgpgYGB7cn0KCiMgQWRkIGNvbHVtbiB3aXRoIHVuaXF1ZSBpZHMgKGRvbid0IG5lZWQgdG8gY2hhbmdlKQppcmlzJEZsb3dlciA8LSAxOm5yb3coaXJpcykKCiMgRmlsbCBpbiB0aGUgX19fIHRvIHByb2R1Y2UgdG8gdGhlIGNvcnJlY3QgaXJpcy53aWRlIGRhdGFzZXQKaXJpcy53aWRlIDwtIGlyaXMgJT4lCiAgZ2F0aGVyKGtleSwgdmFsdWUsIC1TcGVjaWVzLCAtRmxvd2VyKSAlPiUKICBzZXBhcmF0ZShrZXksIGMoIlBhcnQiLCAiTWVhc3VyZSIpLCAiXFwuIikgJT4lCiAgc3ByZWFkKE1lYXN1cmUsIHZhbHVlKQpgYGAKCkFsbCBhYm91dCBhZXN0aGV0aWNzLCBwYXJ0IDEKSW4gdGhlIHZpZGVvIHlvdSBzYXcgOSB2aXNpYmxlIGFlc3RoZXRpY3MuIExldCdzIGFwcGx5IHRoZW0gdG8gYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSAtIHRoZSBjeWxpbmRlcnMgaW4gbXRjYXJzLCBjeWwuCgooWW91J2xsIGNvbnNpZGVyIGxpbmUgdHlwZSB3aGVuIHlvdSBlbmNvdW50ZXIgbGluZSBwbG90cyBpbiB0aGUgbmV4dCBjaGFwdGVyKS4KClRoZXNlIGFyZSB0aGUgYWVzdGhldGljcyB5b3UgY2FuIGNvbnNpZGVyIHdpdGhpbiBhZXMoKSBpbiB0aGlzIGNoYXB0ZXI6IHgsIHksIGNvbG9yLCBmaWxsLCBzaXplLCBhbHBoYSwgbGFiZWxzIGFuZCBzaGFwZS4KCkluIHRoZSBmb2xsb3dpbmcgZXhlcmNpc2UgeW91IGNhbiBhc3N1bWUgdGhhdCB0aGUgY3lsIGNvbHVtbiBpcyBjYXRlZ29yaWNhbC4gSXQgaGFzIGFscmVhZHkgYmVlbiB0cmFuc2Zvcm1lZCBpbnRvIGEgZmFjdG9yIGZvciB5b3UuCgpgYGB7cn0KIyAxIC0gTWFwIG1wZyB0byB4IGFuZCBjeWwgdG8geQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IG1wZywgeSA9IGN5bCkpICsKICBnZW9tX3BvaW50KCkKICAKIyAyIC0gUmV2ZXJzZTogTWFwIGN5bCB0byB4IGFuZCBtcGcgdG8geQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGN5bCwgeSA9IG1wZykpICsKICBnZW9tX3BvaW50KCkKCiMgMyAtIE1hcCB3dCB0byB4LCBtcGcgdG8geSBhbmQgY3lsIHRvIGNvbApnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2xvciA9IGN5bCkpICsKICBnZW9tX3BvaW50KCkKCiMgNCAtIENoYW5nZSBzaGFwZSBhbmQgc2l6ZSBvZiB0aGUgcG9pbnRzIGluIHRoZSBhYm92ZSBwbG90CmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGNvbG9yID0gY3lsKSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAxLCBzaXplID0gNCkKYGBgCgpBbGwgYWJvdXQgYWVzdGhldGljcywgcGFydCAyClRoZSBjb2xvciBhZXN0aGV0aWMgdHlwaWNhbGx5IGNoYW5nZXMgdGhlIG91dHNpZGUgb3V0bGluZSBvZiBhbiBvYmplY3QgYW5kIHRoZSBmaWxsIGFlc3RoZXRpYyBpcyB0eXBpY2FsbHkgdGhlIGluc2lkZSBzaGFkaW5nLiBIb3dldmVyLCBhcyB5b3Ugc2F3IGluIHRoZSBsYXN0IGV4ZXJjaXNlLCBnZW9tX3BvaW50KCkgaXMgYW4gZXhjZXB0aW9uLiBIZXJlIHlvdSB1c2UgY29sb3IsIGluc3RlYWQgb2YgZmlsbCBmb3IgdGhlIGluc2lkZSBvZiB0aGUgcG9pbnQuIEJ1dCBpdCdzIGEgYml0IHN1YnRsZXIgdGhhbiB0aGF0LgoKV2hpY2ggc2hhcGUgdG8gdXNlPyBUaGUgZGVmYXVsdCBnZW9tX3BvaW50KCkgdXNlcyBzaGFwZSA9IDE5IChhIHNvbGlkIGNpcmNsZSB3aXRoIGFuIG91dGxpbmUgdGhlIHNhbWUgY29sb3VyIGFzIHRoZSBpbnNpZGUpLiBHb29kIGFsdGVybmF0aXZlcyBhcmUgc2hhcGUgPSAxIChob2xsb3cpIGFuZCBzaGFwZSA9IDE2IChzb2xpZCwgbm8gb3V0bGluZSkuIFRoZXNlIGFsbCB1c2UgdGhlIGNvbCBhZXN0aGV0aWMgKGRvbid0IGZvcmdldCB0byBzZXQgYWxwaGEgZm9yIHNvbGlkIHBvaW50cykuCgpBIHJlYWxseSBuaWNlIGFsdGVybmF0aXZlIGlzIHNoYXBlID0gMjEgd2hpY2ggYWxsb3dzIHlvdSB0byB1c2UgYm90aCBmaWxsIGZvciB0aGUgaW5zaWRlIGFuZCBjb2wgZm9yIHRoZSBvdXRsaW5lISBUaGlzIGlzIGEgZ3JlYXQgbGl0dGxlIHRyaWNrIGZvciB3aGVuIHlvdSB3YW50IHRvIG1hcCB0d28gYWVzdGhldGljcyB0byBhIGRvdC4KCldoYXQgaGFwcGVucyB3aGVuIHlvdSB1c2UgdGhlIHdyb25nIGFlc3RoZXRpYyBtYXBwaW5nPyBUaGlzIGlzIGEgdmVyeSBjb21tb24gbWlzdGFrZSEgVGhlIGNvZGUgZnJvbSB0aGUgcHJldmlvdXMgZXhlcmNpc2UgaXMgaW4gdGhlIGVkaXRvci4gVXNpbmcgdGhpcyBhcyB5b3VyIHN0YXJ0aW5nIHBvaW50IGNvbXBsZXRlIHRoZSBpbnN0cnVjdGlvbnMuCgpgYGB7cn0KIyBhbSBhbmQgY3lsIGFyZSBmYWN0b3JzLCB3dCBpcyBudW1lcmljCmNsYXNzKG10Y2FycyRhbSkKY2xhc3MobXRjYXJzJGN5bCkKY2xhc3MobXRjYXJzJHd0KQoKIyBGcm9tIHRoZSBwcmV2aW91cyBleGVyY2lzZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2wgPSBjeWwpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDEsIHNpemUgPSA0KQoKIyAxIC0gTWFwIGN5bCB0byBmaWxsCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGZpbGwgPSBjeWwpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDEsIHNpemUgPSA0KQoKIyAyIC0gQ2hhbmdlIHNoYXBlIGFuZCBhbHBoYSBvZiB0aGUgcG9pbnRzIGluIHRoZSBhYm92ZSBwbG90CmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGZpbGwgPSBjeWwpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgYWxwaGEgPSAwLjYpCgojIDMgLSBNYXAgYW0gdG8gY29sIGluIHRoZSBhYm92ZSBwbG90CmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGZpbGwgPSBjeWwsIGNvbD1hbSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBhbHBoYSA9IDAuNikKYGBgCgpBbGwgYWJvdXQgYWVzdGhldGljcywgcGFydCAzCk5vdyB0aGF0IHlvdSd2ZSBnb3Qgc29tZSBwcmFjdGljZSB3aXRoIGluY3JlbWVudGFsbHkgYnVpbGRpbmcgdXAgcGxvdHMsIHlvdSBjYW4gdHJ5IHRvIGRvIGl0IGZyb20gc2NyYXRjaCEgVGhlIG10Y2FycyBkYXRhc2V0IGlzIHByZS1sb2FkZWQgaW4gdGhlIHdvcmtzcGFjZS4KCmBgYHtyfQojIE1hcCBjeWwgdG8gc2l6ZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeD13dCwgeT1tcGcsIHNpemUgPSBjeWwpKSArCiAgZ2VvbV9wb2ludCgpCgojIE1hcCBjeWwgdG8gYWxwaGEKZ2dwbG90KG10Y2FycywgYWVzKHg9d3QsIHk9bXBnLCBhbHBoYT1jeWwpKSArCiAgZ2VvbV9wb2ludCgpCgojIE1hcCBjeWwgdG8gc2hhcGUgCmdncGxvdChtdGNhcnMsIGFlcyh4PXd0LCB5PW1wZywgc2hhcGU9Y3lsKSkgKwogIGdlb21fcG9pbnQoKQoKIyBNYXAgY3lsIHRvIGxhYmVsCmdncGxvdChtdGNhcnMsIGFlcyh4PXd0LCB5PW1wZywgbGFiZWw9Y3lsKSApKwogIGdlb21fdGV4dCgpCmBgYAoKQWxsIGFib3V0IGF0dHJpYnV0ZXMsIHBhcnQgMQpJbiB0aGUgdmlkZW8geW91IHNhdyB0aGF0IHlvdSBjYW4gdXNlIGFsbCB0aGUgYWVzdGhldGljcyBhcyBhdHRyaWJ1dGVzLiBMZXQncyBzZWUgaG93IHRoaXMgd29ya3Mgd2l0aCB0aGUgYWVzdGhldGljcyB5b3UgdXNlZCBpbiB0aGUgcHJldmlvdXMgZXhlcmNpc2VzOiB4LCB5LCBjb2xvciwgZmlsbCwgc2l6ZSwgYWxwaGEsIGxhYmVsIGFuZCBzaGFwZS4KClRoaXMgdGltZSB5b3UnbGwgdXNlIHRoZXNlIGFyZ3VtZW50cyB0byBzZXQgYXR0cmlidXRlcyBvZiB0aGUgcGxvdCwgbm90IGFlc3RoZXRpY3MuIEhvd2V2ZXIsIHRoZXJlIGFyZSBzb21lIHBpdGZhbGxzIHlvdSdsbCBoYXZlIHRvIHdhdGNoIG91dCBmb3I6IHRoZXNlIGF0dHJpYnV0ZXMgY2FuIG92ZXJ3cml0ZSB0aGUgYWVzdGhldGljcyBvZiB5b3VyIHBsb3QhCgpBIHdvcmQgYWJvdXQgc2hhcGVzOiBJbiB0aGUgZXhlcmNpc2UgIkFsbCBhYm91dCBhZXN0aGV0aWNzLCBwYXJ0IDIiLCB5b3Ugc2F3IHRoYXQgc2hhcGUgPSAyMSByZXN1bHRzIGluIGEgcG9pbnQgdGhhdCBoYXMgYSBmaWxsIGFuZCBhbiBvdXRsaW5lLiBTaGFwZXMgaW4gUiBjYW4gaGF2ZSBhIHZhbHVlIGZyb20gMS0yNS4gU2hhcGVzIDEtMjAgY2FuIG9ubHkgYWNjZXB0IGEgY29sb3IgYWVzdGhldGljLCBidXQgc2hhcGVzIDIxLTI1IGhhdmUgYm90aCBhIGNvbG9yIGFuZCBhIGZpbGwgYWVzdGhldGljLiBTZWUgdGhlIHBjaCBhcmd1bWVudCBpbiBwYXIoKSBmb3IgZnVydGhlciBkaXNjdXNzaW9uLgoKQSB3b3JkIGFib3V0IGhleGFkZWNpbWFsIGNvbG91cnM6IEhleGFkZWNpbWFsLCBsaXRlcmFsbHkgInJlbGF0ZWQgdG8gMTYiLCBpcyBhIGJhc2UtMTYgYWxwaGFudW1lcmljIGNvdW50aW5nIHN5c3RlbS4gSW5kaXZpZHVhbCB2YWx1ZXMgY29tZSBmcm9tIHRoZSByYW5nZXMgMC05IGFuZCBBLUYuIFRoaXMgbWVhbnMgdGhlcmUgYXJlIDI1NiBwb3NzaWJsZSB0d28tZGlnaXQgdmFsdWVzIChpLmUuIDAwIC0gRkYpLiBIZXhhZGVjaW1hbCBjb2xvdXJzIHVzZSB0aGlzIHN5c3RlbSB0byBzcGVjaWZ5IGEgc2l4LWRpZ2l0IGNvZGUgZm9yIFJlZCwgR3JlZW4gYW5kIEJsdWUgdmFsdWVzICgiI1JSR0dCQiIpIG9mIGEgY29sb3VyIChpLmUuIFB1cmUgYmx1ZTogIiMwMDAwRkYiLCBibGFjazogIiMwMDAwMDAiLCB3aGl0ZTogIiNGRkZGRkYiKS4gUiBjYW4gYWNjZXB0IGhleCBjb2RlcyBhcyB2YWxpZCBjb2xvdXJzLgoKYGBge3J9CiMgRGVmaW5lIGEgaGV4YWRlY2ltYWwgY29sb3IKbXlfY29sb3IgPC0gIiM0QUJFRkYiCgojIDEgLSBGaXJzdCBzY2F0dGVyIHBsb3QsIHdpdGggY29sIGFlc3RoZXRpYzoKZ2dwbG90KG10Y2FycywgYWVzKHggPSB3dCwgeSA9IG1wZywgY29sb3IgPSBjeWwpKSArCmdlb21fcG9pbnQoKQoKIyAyIC0gUGxvdCAxLCBidXQgc2V0IGNvbCBhdHRyaWJ1dGVzIGluIGdlb20gbGF5ZXI6CmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGNvbG9yID0gY3lsKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSBteV9jb2xvcikKCiMgMyAtIFBsb3QgMiwgd2l0aCBmaWxsIGluc3RlYWQgb2YgY29sIGFlc3RoZXRpYywgcGx1dCBzaGFwZSBhbmQgc2l6ZSBhdHRyaWJ1dGVzIGluIGdlb20gbGF5ZXIuCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGZpbGwgPSBjeWwpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9IG15X2NvbG9yLCBzaXplID0gMTAsIHNoYXBlID0gMjMpCgoKYGBgCgpBbGwgYWJvdXQgYXR0cmlidXRlcywgcGFydCAyCkluIHRoZSB2aWRlb3MgeW91IHNhdyB0aGF0IHlvdSBjYW4gdXNlIGFsbCB0aGUgYWVzdGhldGljcyBhcyBhdHRyaWJ1dGVzLiBMZXQncyBzZWUgaG93IHRoaXMgd29ya3Mgd2l0aCB0aGUgYWVzdGhldGljcyB5b3UgdXNlZCBpbiB0aGUgcHJldmlvdXMgZXhlcmNpc2VzOiB4LCB5LCBjb2xvciwgZmlsbCwgc2l6ZSwgYWxwaGEsIGxhYmVsIGFuZCBzaGFwZS4KCkluIHRoaXMgZXhlcmNpc2UgeW91IHdpbGwgc2V0IGFsbCBraW5kcyBvZiBhdHRyaWJ1dGVzIG9mIHRoZSBwb2ludHMhCgpZb3Ugd2lsbCBjb250aW51ZSB0byB3b3JrIHdpdGggbXRjYXJzLgoKYGBge3J9CiMgRXhwYW5kIHRvIGRyYXcgcG9pbnRzIHdpdGggYWxwaGEgMC41CmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGZpbGwgPSBjeWwpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkKCiAgCiMgRXhwYW5kIHRvIGRyYXcgcG9pbnRzIHdpdGggc2hhcGUgMjQgYW5kIGNvbG9yIHllbGxvdwpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBmaWxsID0gY3lsKSkgICsKICBnZW9tX3BvaW50KGNvbG9yID0gInllbGxvdyIsIHNoYXBlID0gMjQpCgogIAojIEV4cGFuZCB0byBkcmF3IHRleHQgd2l0aCBsYWJlbCByb3duYW1lcyhtdGNhcnMpIGFuZCBjb2xvciByZWQKZ2dwbG90KG10Y2FycywgYWVzKHggPSB3dCwgeSA9IG1wZywgZmlsbCA9IGN5bCkpICsKICBnZW9tX3RleHQobGFiZWwgPSByb3duYW1lcyhtdGNhcnMpLCBjb2xvciA9ICJyZWQiKQoKYGBgCgpHb2luZyBhbGwgb3V0CkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGdyYWR1YWxseSBhZGQgbW9yZSBhZXN0aGV0aWNzIGxheWVycyB0byB0aGUgcGxvdC4gWW91J3JlIHN0aWxsIHdvcmtpbmcgd2l0aCB0aGUgbXRjYXJzIGRhdGFzZXQsIGJ1dCB0aGlzIHRpbWUgeW91J3JlIHVzaW5nIG1vcmUgZmVhdHVyZXMgb2YgdGhlIGNhcnMuIEZvciBjb21wbGV0ZW5lc3MsIGhlcmUgaXMgYSBsaXN0IG9mIGFsbCB0aGUgZmVhdHVyZXMgb2YgdGhlIG9ic2VydmF0aW9ucyBpbiBtdGNhcnM6CgptcGcgLS0gTWlsZXMvKFVTKSBnYWxsb24KY3lsIC0tIE51bWJlciBvZiBjeWxpbmRlcnMKZGlzcCAtLSBEaXNwbGFjZW1lbnQgKGN1LmluLikKaHAgLS0gR3Jvc3MgaG9yc2Vwb3dlcgpkcmF0IC0tIFJlYXIgYXhsZSByYXRpbwp3dCAtLSBXZWlnaHQgKGxiLzEwMDApCnFzZWMgLS0gMS80IG1pbGUgdGltZQp2cyAtLSBWL1MgZW5naW5lLgphbSAtLSBUcmFuc21pc3Npb24gKDAgPSBhdXRvbWF0aWMsIDEgPSBtYW51YWwpCmdlYXIgLS0gTnVtYmVyIG9mIGZvcndhcmQgZ2VhcnMKY2FyYiAtLSBOdW1iZXIgb2YgY2FyYnVyZXRvcnMKTm90aWNlIHRoYXQgYWRkaW5nIG1vcmUgYWVzdGhldGljcyB0byB5b3VyIHBsb3QgaXMgbm90IGFsd2F5cyBhIGdvb2QgaWRlYS4gQWRkaW5nIGFlc3RoZXRpYyBtYXBwaW5ncyB0byBhIHBsb3Qgd2lsbCBpbmNyZWFzZSBpdHMgY29tcGxleGl0eSwgYW5kIHRodXMgZGVjcmVhc2UgaXRzIHJlYWRhYmlsaXR5LgoKYGBge3J9CiMgTWFwIG1wZyBvbnRvIHgsIHFzZWMgb250byB5IGFuZCBmYWN0b3IoY3lsKSBvbnRvIGNvbApnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IG1wZywgeSA9IHFzZWMsIGNvbCA9IGZhY3RvcihjeWwpKSkgKwogIGdlb21fcG9pbnQoKQoKIyBBZGQgbWFwcGluZzogZmFjdG9yKGFtKSBvbnRvIHNoYXBlCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gbXBnLCB5ID0gcXNlYywgY29sID0gZmFjdG9yKGN5bCksIHNoYXBlID0gZmFjdG9yKGFtKSkpICsKICBnZW9tX3BvaW50KCkKCgojIEFkZCBtYXBwaW5nOiAoaHAvd3QpIG9udG8gc2l6ZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IG1wZywgeSA9IHFzZWMsIGNvbCA9IGZhY3RvcihjeWwpLCBzaGFwZSA9IGZhY3RvcihhbSksIHNpemUgPSAoaHAvd3QpKSkgKwogIGdlb21fcG9pbnQoKQoKYGBgCgpQb3NpdGlvbgpZb3Ugc2F3IGhvdyBqaXR0ZXJpbmcgd29ya2VkIGluIHRoZSB2aWRlbywgYnV0IGJhciBwbG90cyBzdWZmZXIgZnJvbSB0aGVpciBvd24gaXNzdWVzIG9mIG92ZXJwbG90dGluZywgYXMgeW91J2xsIHNlZSBoZXJlLiBVc2UgdGhlICJzdGFjayIsICJmaWxsIiBhbmQgImRvZGdlIiBwb3NpdGlvbnMgdG8gcmVwcm9kdWNlIHRoZSBwbG90IGluIHRoZSB2aWV3ZXIuCgpUaGUgZ2dwbG90MiBiYXNlIGxheWVycyAoZGF0YSBhbmQgYWVzdGhldGljcykgaGF2ZSBhbHJlYWR5IGJlZW4gY29kZWQ7IHRoZXkncmUgc3RvcmVkIGluIGEgdmFyaWFibGUgY3lsLmFtLiBJdCBsb29rcyBsaWtlIHRoaXM6CgpjeWwuYW0gPC0gZ2dwbG90KG10Y2FycywgYWVzKHggPSBmYWN0b3IoY3lsKSwgZmlsbCA9IGZhY3RvcihhbSkpKQoKYGBge3J9CmN5bC5hbSA8LSBnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGZhY3RvcihjeWwpLCBmaWxsID0gZmFjdG9yKGFtKSkpCgojIFRoZSBiYXNlIGxheWVyLCBjeWwuYW0sIGlzIGF2YWlsYWJsZSBmb3IgeW91CiMgQWRkIGdlb20gKHBvc2l0aW9uID0gInN0YWNrIiBieSBkZWZhdWx0KQpjeWwuYW0gKyAKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIpCgojIEZpbGwgLSBzaG93IHByb3BvcnRpb24KY3lsLmFtICsgCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICAKCiMgRG9kZ2luZyAtIHByaW5jaXBsZXMgb2Ygc2ltaWxhcml0eSBhbmQgcHJveGltaXR5CmN5bC5hbSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKSAKCiMgQ2xlYW4gdXAgdGhlIGF4ZXMgd2l0aCBzY2FsZV8gZnVuY3Rpb25zCnZhbCA9IGMoIiNFNDFBMUMiLCAiIzM3N0VCOCIpCmxhYiA9IGMoIk1hbnVhbCIsICJBdXRvbWF0aWMiKQpjeWwuYW0gKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikgKwogIHNjYWxlX3hfZGlzY3JldGUoIkN5bGluZGVycyIpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKCJOdW1iZXIiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoIlRyYW5zbWlzc2lvbiIsIAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IHZhbCwKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBsYWIpIApgYGAKClNldHRpbmcgYSBkdW1teSBhZXN0aGV0aWMKSW4gdGhlIGxhc3QgY2hhcHRlciB5b3Ugc2F3IHRoYXQgYWxsIHRoZSB2aXNpYmxlIGFlc3RoZXRpY3MgY2FuIHNlcnZlIGFzIGF0dHJpYnV0ZXMgYW5kIGFlc3RoZXRpY3MsIGJ1dCBJIHZlcnkgY29udmVuaWVudGx5IGxlZnQgb3V0IHggYW5kIHkuIFRoYXQncyBiZWNhdXNlIGFsdGhvdWdoIHlvdSBjYW4gbWFrZSB1bml2YXJpYXRlIHBsb3RzIChzdWNoIGFzIGhpc3RvZ3JhbXMsIHdoaWNoIHlvdSdsbCBnZXQgdG8gaW4gdGhlIG5leHQgY2hhcHRlciksIGEgeS1heGlzIHdpbGwgYWx3YXlzIGJlIHByb3ZpZGVkLCBldmVuIGlmIHlvdSBkaWRuJ3QgYXNrIGZvciBpdC4KCkluIHRoZSBiYXNlIHBhY2thZ2UgeW91IGNhbiBtYWtlIHVuaXZhcmlhdGUgcGxvdHMgd2l0aCBzdHJpcGNoYXJ0KCkgKHNob3duIGluIHRoZSB2aWV3ZXIpIGRpcmVjdGx5IGFuZCBpdCB3aWxsIHRha2UgY2FyZSBvZiBhIGZha2UgeSBheGlzIGZvciB1cy4gU2luY2UgdGhpcyBpcyB1bml2YXJpYXRlIGRhdGEsIHRoZXJlIGlzIG5vIHJlYWwgeSBheGlzLgoKWW91IGNhbiBnZXQgdGhlIHNhbWUgdGhpbmcgaW4gZ2dwbG90MiwgYnV0IGl0J3MgYSBiaXQgbW9yZSBjdW1iZXJzb21lLiBUaGUgb25seSByZWFzb24geW91J2QgcmVhbGx5IHdhbnQgdG8gZG8gdGhpcyBpcyBpZiB5b3Ugd2VyZSBtYWtpbmcgbWFueSBwbG90cyBhbmQgeW91IHdhbnRlZCB0aGVtIHRvIGJlIGluIHRoZSBzYW1lIHN0eWxlLCBvciB5b3Ugd2FudGVkIHRvIHRha2UgYWR2YW50YWdlIG9mIGFuIGFlc3RoZXRpYyBtYXBwaW5nIChlLmcuIGNvbG91cikuCgpgYGB7cn0KIyAxIC0gQ3JlYXRlIGppdHRlcmVkIHBsb3Qgb2YgbXRjYXJzLCBtcGcgb250byB4LCAwIG9udG8geQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IG1wZywgeSA9IDApKSArCiAgZ2VvbV9qaXR0ZXIoKQoKIyAyIC0gQWRkIGZ1bmN0aW9uIHRvIGNoYW5nZSB5IGF4aXMgbGltaXRzCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gbXBnLCB5ID0gMCkpICsKICBnZW9tX2ppdHRlcigpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMiwyKSkKYGBgCgpPdmVycGxvdHRpbmcgMSAtIFBvaW50IHNoYXBlIGFuZCB0cmFuc3BhcmVuY3kKSW4gdGhlIHByZXZpb3VzIHNlY3Rpb24geW91IHNhdyB0aGF0IHRoZXJlIGFyZSBsb3RzIG9mIHdheXMgdG8gdXNlIGFlc3RoZXRpY3MuIFBlcmhhcHMgdG9vIG1hbnksIGJlY2F1c2UgYWx0aG91Z2ggdGhleSBhcmUgcG9zc2libGUsIHRoZXkgYXJlIG5vdCBhbGwgcmVjb21tZW5kZWQuIExldCdzIHRha2UgYSBsb29rIGF0IHdoYXQgd29ya3MgYW5kIHdoYXQgZG9lc24ndC4KClNvIGZhciB5b3UndmUgZm9jdXNlZCBvbiBzY2F0dGVyIHBsb3RzIHNpbmNlIHRoZXkgYXJlIGludHVpdGl2ZSwgZWFzaWx5IHVuZGVyc3Rvb2QgYW5kIHZlcnkgY29tbW9uLiBBIG1ham9yIGNvbnNpZGVyYXRpb24gaW4gYW55IHNjYXR0ZXIgcGxvdCBpcyBkZWFsaW5nIHdpdGggb3ZlcnBsb3R0aW5nLiBZb3UnbGwgZW5jb3VudGVyIHRoaXMgdG9waWMgYWdhaW4gaW4gdGhlIGdlb21ldHJpZXMgbGF5ZXIsIGJ1dCB5b3UgY2FuIGFscmVhZHkgbWFrZSBzb21lIGFkanVzdG1lbnRzIGhlcmUuCgpZb3UnbGwgaGF2ZSB0byBkZWFsIHdpdGggb3ZlcnBsb3R0aW5nIHdoZW4geW91IGhhdmU6CgpMYXJnZSBkYXRhc2V0cywKSW1wcmVjaXNlIGRhdGEgYW5kIHNvIHBvaW50cyBhcmUgbm90IGNsZWFybHkgc2VwYXJhdGVkIG9uIHlvdXIgcGxvdCAoeW91IHNhdyB0aGlzIGluIHRoZSB2aWRlbyB3aXRoIHRoZSBpcmlzIGRhdGFzZXQpLApJbnRlcnZhbCBkYXRhIChpLmUuIGRhdGEgYXBwZWFycyBhdCBmaXhlZCB2YWx1ZXMpLCBvcgpBbGlnbmVkIGRhdGEgdmFsdWVzIG9uIGEgc2luZ2xlIGF4aXMuCk9uZSB2ZXJ5IGNvbW1vbiB0ZWNobmlxdWUgdGhhdCBJJ2QgcmVjb21tZW5kIHRvIGFsd2F5cyB1c2Ugd2hlbiB5b3UgaGF2ZSBzb2xpZCBzaGFwZXMgaXQgdG8gdXNlIGFscGhhIGJsZW5kaW5nIChpLmUuIGFkZGluZyB0cmFuc3BhcmVuY3kpLiBBbiBhbHRlcm5hdGl2ZSBpcyB0byB1c2UgaG9sbG93IHNoYXBlcy4gVGhlc2UgYXJlIGFkanVzdG1lbnRzIHRvIG1ha2UgYmVmb3JlIGV2ZW4gd29ycnlpbmcgYWJvdXQgcG9zaXRpb25pbmcuIFRoaXMgYWRkcmVzc2VzIHRoZSBmaXJzdCBwb2ludCBhcyBhYm92ZSwgd2hpY2ggeW91J2xsIHNlZSBhZ2FpbiBpbiB0aGUgbmV4dCBleGVyY2lzZS4KCmBgYHtyfQojIEJhc2ljIHNjYXR0ZXIgcGxvdDogd3Qgb24geC1heGlzIGFuZCBtcGcgb24geS1heGlzOyBtYXAgY3lsIHRvIGNvbApnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2xvciA9IGN5bCApKSArCiAgZ2VvbV9wb2ludChzaXplID0gNCkKCiMgSG9sbG93IGNpcmNsZXMgLSBhbiBpbXByb3ZlbWVudApnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2xvciA9IGN5bCkpICsKICBnZW9tX3BvaW50KHNpemUgPSA0LCBzaGFwZSA9IDEpCgojIEFkZCB0cmFuc3BhcmVuY3kgLSB2ZXJ5IG5pY2UKZ2dwbG90KG10Y2FycywgYWVzKHggPSB3dCwgeSA9IG1wZywgY29sb3IgPSBjeWwpKSArCiAgZ2VvbV9wb2ludChzaXplID0gNCwgYWxwaGEgPSAwLjYpCgpgYGAKCk92ZXJwbG90dGluZyAyIC0gYWxwaGEgd2l0aCBsYXJnZSBkYXRhc2V0cwpJbiBhIHByZXZpb3VzIGV4ZXJjaXNlIHdlIGRlZmluZWQgZm91ciBzaXR1YXRpb25zIGluIHdoaWNoIHlvdSdkIGhhdmUgdG8gYWRqdXN0IGZvciBvdmVycGxvdHRpbmcuIFlvdSdsbCBjb25zaWRlciB0aGUgbGFzdCB0d28gaGVyZSB3aXRoIHRoZSBkaWFtb25kcyBkYXRhc2V0OgoKTGFyZ2UgZGF0YXNldHMuCkFsaWduZWQgZGF0YSB2YWx1ZXMgb24gYSBzaW5nbGUgYXhpcwoKYGBge3J9CiMgU2NhdHRlciBwbG90OiBjYXJhdCAoeCksIHByaWNlICh5KSwgY2xhcml0eSAoY29sb3IpCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlLCBjb2xvciA9IGNsYXJpdHkpKSArCiAgZ2VvbV9wb2ludCgpCgojIEFkanVzdCBmb3Igb3ZlcnBsb3R0aW5nCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlLCBjb2xvciA9IGNsYXJpdHkpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkKCgojIFNjYXR0ZXIgcGxvdDogY2xhcml0eSAoeCksIGNhcmF0ICh5KSwgcHJpY2UgKGNvbG9yKQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2xhcml0eSwgeSA9IGNhcmF0LCBjb2xvciA9IHByaWNlKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpCgojIERvdCBwbG90IHdpdGggaml0dGVyaW5nCmdncGxvdChkaWFtb25kcywgYWVzKHggPSBjbGFyaXR5LCB5ID0gY2FyYXQsIGNvbG9yID0gcHJpY2UpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSwgcG9zaXRpb24gPSAiaml0dGVyIikKYGBgCgpTY2F0dGVyIHBsb3RzIGFuZCBqaXR0ZXJpbmcgKDEpCllvdSBhbHJlYWR5IHNhdyBhIGZldyBleGFtcGxlcyB1c2luZyBnZW9tX3BvaW50KCkgd2hlcmUgdGhlIHJlc3VsdCB3YXMgbm90IGEgc2NhdHRlciBwbG90LiBGb3IgZXhhbXBsZSwgaW4gdGhlIHBsb3Qgc2hvd24gaW4gdGhlIHZpZXdlciBhIGNvbnRpbnVvdXMgdmFyaWFibGUsIHd0LCBpcyBtYXBwZWQgdG8gdGhlIHkgYWVzdGhldGljLCBhbmQgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSwgY3lsLCBpcyBtYXBwZWQgdG8gdGhlIHggYWVzdGhldGljLiBUaGlzIGFsc28gbGVhZHMgdG8gb3Zlci1wbG90dGluZywgc2luY2UgdGhlIHBvaW50cyBhcmUgYXJyYW5nZWQgb24gYSBzaW5nbGUgeCBwb3NpdGlvbi4gWW91IHByZXZpb3VzbHkgZGVhbHQgd2l0aCBvdmVycGxvdHRpbmcgYnkgc2V0dGluZyB0aGUgcG9zaXRpb24gPSBqaXR0ZXIgaW5zaWRlIGdlb21fcG9pbnQoKS4gTGV0J3MgbG9vayBhdCBzb21lIG90aGVyIHNvbHV0aW9ucyBoZXJlLgoKYGBge3J9CiMgU2hvd24gaW4gdGhlIHZpZXdlcjoKZ2dwbG90KG10Y2FycywgYWVzKHggPSBjeWwsIHkgPSB3dCkpICsKICBnZW9tX3BvaW50KCkKCiMgU29sdXRpb25zOgojIDEgLSBXaXRoIGdlb21faml0dGVyKCkKZ2dwbG90KG10Y2FycywgYWVzKHggPSBjeWwsIHkgPSB3dCkpICsKICBnZW9tX2ppdHRlcigpCgojIDIgLSBTZXQgd2lkdGggaW4gZ2VvbV9qaXR0ZXIoKQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGN5bCwgeSA9IHd0KSkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4xKQoKIyAzIC0gU2V0IHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKCkgaW4gZ2VvbV9wb2ludCgpICgpCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gY3lsLCB5ID0gd3QpKSArCiAgZ2VvbV9wb2ludChwb3NpaXRvbiA9IHBvc2l0aW9uX2ppdHRlcigwLjEpKQpgYGAKCgpIaXN0b2dyYW1zCkhpc3RvZ3JhbXMgYXJlIG9uZSBvZiB0aGUgbW9zdCBjb21tb24gYW5kIGludHVpdGl2ZSB3YXlzIG9mIHNob3dpbmcgZGlzdHJpYnV0aW9ucy4gSW4gdGhpcyBleGVyY2lzZSB5b3UnbGwgdXNlIHRoZSBtdGNhcnMgZGF0YSBmcmFtZSB0byBleHBsb3JlIHR5cGljYWwgdmFyaWF0aW9ucyBvZiBzaW1wbGUgaGlzdG9ncmFtcy4gQnV0IGZpcnN0LCBzb21lIGJhY2tncm91bmQ6CgpUaGUgeCBheGlzL2Flc3RoZXRpYzogVGhlIGRvY3VtZW50YXRpb24gZm9yIGdlb21faGlzdG9ncmFtKCkgc3RhdGVzIHRoZSBhcmd1bWVudCBzdGF0ID0gImJpbiIgYXMgYSBkZWZhdWx0LiBSZWNhbGwgdGhhdCBoaXN0b2dyYW1zIGN1dCB1cCBhIGNvbnRpbnVvdXMgdmFyaWFibGUgaW50byBkaXNjcmV0ZSBiaW5zIC0gdGhhdHMgd2hhdCB0aGUgc3RhdCAiYmluIiBpcyBkb2luZy4gWW91IGFsd2F5cyBnZXQgMzAgZXZlbmx5LXNpemVkIGJpbnMgYnkgZGVmYXVsdCwgd2hpY2ggaXMgc3BlY2lmaWVkIHdpdGggdGhlIGRlZmF1bHQgYXJndW1lbnQgYmlud2lkdGggPSByYW5nZS8zMC4gVGhpcyBpcyBhIHByZXR0eSBnb29kIHN0YXJ0aW5nIHBvaW50IGlmIHlvdSBkb24ndCBrbm93IGFueXRoaW5nIGFib3V0IHRoZSB2YXJpYWJsZSBiZWluZyBwbG90ZWQgYW5kIHdhbnQgdG8gc3RhcnQgZXhwbG9yaW5nLgoKVGhlIHkgYXhpcy9hZXN0aGV0aWM6IGdlb21faGlzdG9ncmFtKCkgb25seSByZXF1aXJlcyBvbmUgYWVzdGhldGljOiB4LiBCdXQgdGhlcmUgaXMgY2xlYXJseSBhIHkgYXhpcyBvbiB5b3VyIHBsb3QsIHNvIHdoZXJlIGRvZXMgaXQgY29tZSBmcm9tPyBBY3R1YWxseSwgdGhlcmUgaXMgYSB2YXJpYWJsZSBtYXBwZWQgdG8gdGhlIHkgYWVzdGhldGljLCBpdCdzIGNhbGxlZCAuLmNvdW50Li4uIFdoZW4gZ2VvbV9oaXN0b2dyYW0oKSBleGVjdXRlZCB0aGUgYmlubmluZyBzdGF0aXN0aWMgKHNlZSBhYm92ZSksIGl0IG5vdCBvbmx5IGN1dCB1cCB0aGUgZGF0YSBpbnRvIGRpc2NyZXRlIGJpbnMsIGJ1dCBpdCBhbHNvIGNvdW50ZWQgaG93IG1hbnkgdmFsdWVzIGFyZSBpbiBlYWNoIGJpbi4gU28gdGhlcmUgaXMgYW4gaW50ZXJuYWwgZGF0YSBmcmFtZSB3aGVyZSB0aGlzIGluZm9ybWF0aW9uIGlzIHN0b3JlZC4gVGhlIC4uIGNhbGxzIHRoZSB2YXJpYWJsZSBjb3VudCBmcm9tIHRoaXMgaW50ZXJuYWwgZGF0YSBmcmFtZS4gVGhpcyBpcyB3aGF0IGFwcGVhcnMgb24gdGhlIHkgYWVzdGhldGljLiBCdXQgaXQgZ2V0cyBiZXR0ZXIhIFRoZSBkZW5zaXR5IGhhcyBhbHNvIGJlZW4gY2FsY3VsYXRlZC4gVGhpcyBpcyB0aGUgcHJvcG9ydGlvbmFsIGZyZXF1ZW5jeSBvZiB0aGlzIGJpbiBpbiByZWxhdGlvbiB0byB0aGUgd2hvbGUgZGF0YSBzZXQuIFlvdSB1c2UgLi5kZW5zaXR5Li4gdG8gYWNjZXNzIHRoaXMgaW5mb3JtYXRpb24uCgpgYGB7cn0KIyAxIC0gTWFrZSBhIHVuaXZhcmlhdGUgaGlzdG9ncmFtCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gbXBnKSkgKwogIGdlb21faGlzdG9ncmFtKCkKCiMgMiAtIFBsb3QgMSwgcGx1cyBzZXQgYmlud2lkdGggdG8gMSBpbiB0aGUgZ2VvbSBsYXllcgpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IG1wZykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpCgojIDMgLSBQbG90IDIsIHBsdXMgTUFQIC4uZGVuc2l0eS4uIHRvIHRoZSB5IGFlc3RoZXRpYyAoaS5lLiBpbiBhIHNlY29uZCBhZXMoKSBmdW5jdGlvbikKZ2dwbG90KG10Y2FycywgYWVzKHggPSBtcGcpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAuLmRlbnNpdHkuLiksIGJpbndpZHRoID0gMSkKCiMgNCAtIHBsb3QgMywgcGx1cyBTRVQgdGhlIGZpbGwgYXR0cmlidXRlIHRvICIjMzc3RUI4IgpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IG1wZykpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSwgYmlud2lkdGggPSAxLCBmaWxsID0gIiMzNzdFQjgiKQpgYGAKClBvc2l0aW9uCkluIHRoZSBwcmV2aW91cyBjaGFwdGVyIHlvdSBzYXcgdGhhdCB0aGVyZSBhcmUgbG90cyBvZiB3YXlzIHRvIHBvc2l0aW9uIHNjYXR0ZXIgcGxvdHMuIExpa2V3aXNlLCB0aGUgZ2VvbV9iYXIoKSBhbmQgZ2VvbV9oaXN0b2dyYW0oKSBnZW9tcyBhbHNvIGhhdmUgYSBwb3NpdGlvbiBhcmd1bWVudCwgd2hpY2ggeW91IGNhbiB1c2UgdG8gc3BlY2lmeSBob3cgdG8gZHJhdyB0aGUgYmFycyBvZiB0aGUgcGxvdC4KClRocmVlIHBvc2l0aW9uIGFyZ3VtZW50cyB3aWxsIGJlIGludHJvZHVjZWQgaGVyZToKCnN0YWNrOiBwbGFjZSB0aGUgYmFycyBvbiB0b3Agb2YgZWFjaCBvdGhlci4gQ291bnRzIGFyZSB1c2VkLiBUaGlzIGlzIHRoZSBkZWZhdWx0IHBvc2l0aW9uLgpmaWxsOiBwbGFjZSB0aGUgYmFycyBvbiB0b3Agb2YgZWFjaCBvdGhlciwgYnV0IHRoaXMgdGltZSB1c2UgcHJvcG9ydGlvbnMuCmRvZGdlOiBwbGFjZSB0aGUgYmFycyBuZXh0IHRvIGVhY2ggb3RoZXIuIENvdW50cyBhcmUgdXNlZC4KSW4gdGhpcyBleGVyY2lzZSB5b3UnbGwgZHJhdyB0aGUgdG90YWwgY291bnQgb2YgY2FycyBoYXZpbmcgYSBnaXZlbiBudW1iZXIgb2YgY3lsaW5kZXJzIChjeWwpLCBhY2NvcmRpbmcgdG8gbWFudWFsIG9yIGF1dG9tYXRpYyB0cmFuc21pc3Npb24gdHlwZSAoYW0pIC0gYXMgc2hvd24gaW4gdGhlIHZpZXdlci4KClNpbmNlLCBpbiB0aGUgYnVpbHQtaW4gbXRjYXJzIGRhdGEgc2V0LCBjeWwgYW5kIGFtIGFyZSBpbnRlZ2VycywgdGhleSBoYXZlIGFscmVhZHkgYmVlbiBjb252ZXJ0ZWQgdG8gZmFjdG9yIHZhcmlhYmxlcyBmb3IgeW91LgoKYGBge3J9CiMgRHJhdyBhIGJhciBwbG90IG9mIGN5bCwgZmlsbGVkIGFjY29yZGluZyB0byBhbQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGN5bCwgZmlsbCA9IGFtKSkgKwogIGdlb21fYmFyKCkKCiMgQ2hhbmdlIHRoZSBwb3NpdGlvbiBhcmd1bWVudCB0byBzdGFjawpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGN5bCwgZmlsbCA9IGFtKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIikKCgojIENoYW5nZSB0aGUgcG9zaXRpb24gYXJndW1lbnQgdG8gZmlsbApnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGN5bCwgZmlsbCA9IGFtKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKQoKCiMgQ2hhbmdlIHRoZSBwb3NpdGlvbiBhcmd1bWVudCB0byBkb2RnZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGN5bCwgZmlsbCA9IGFtKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikKYGBgCgpPdmVybGFwcGluZyBiYXIgcGxvdHMKU28gZmFyIHlvdSd2ZSBzZWVuIHRocmVlIGRpZmZlcmVudCBwb3NpdGlvbnMgZm9yIGJhciBwbG90czogc3RhY2sgKHRoZSBkZWZhdWx0KSwgZG9kZ2UgKHByZWZlcnJlZCksIGFuZCBmaWxsICh0byBzaG93IHByb3BvcnRpb25zKS4KCkhvd2V2ZXIsIHlvdSBjYW4gZ28gb25lIHN0ZXAgZnVydGhlciBieSBhZGp1c3RpbmcgdGhlIGRvZGdpbmcsIHNvIHRoYXQgeW91ciBiYXJzIHBhcnRpYWxseSBvdmVybGFwIGVhY2ggb3RoZXIuIEZvciB0aGlzIGV4YW1wbGUgeW91J2xsIGFnYWluIHVzZSB0aGUgbXRjYXJzIGRhdGFzZXQuIExpa2UgbGFzdCB0aW1lIGN5bCBhbmQgYW0gYXJlIGFscmVhZHkgYXZhaWxhYmxlIGFzIGZhY3RvcnMgaW5zaWRlIG10Y2Fycy4KCkluc3RlYWQgb2YgdXNpbmcgcG9zaXRpb24gPSAiZG9kZ2UiIHlvdSdyZSBnb2luZyB0byB1c2UgcG9zaXRpb25fZG9kZ2UoKSwgbGlrZSB5b3UgZGlkIHdpdGggcG9zaXRpb25faml0dGVyKCkgaW4gdGhlIFNjYXR0ZXIgcGxvdHMgYW5kIGppdHRlcmluZyAoMSkgZXhlcmNpc2UuIEhlcmUsIHlvdSdsbCBzYXZlIHRoaXMgYXMgYW4gb2JqZWN0LCBwb3NuX2QsIHNvIHRoYXQgeW91IGNhbiBlYXNpbHkgcmV1c2UgaXQuCgpSZW1lbWJlciwgdGhlIHJlYXNvbiB5b3Ugd2FudCB0byB1c2UgcG9zaXRpb25fZG9kZ2UoKSAoYW5kIHBvc2l0aW9uX2ppdHRlcigpKSBpcyB0byBzcGVjaWZ5IGhvdyBtdWNoIGRvZGdpbmcgKG9yIGppdHRlcmluZykgeW91IHdhbnQuCgpgYGB7cn0KIyAxIC0gVGhlIGxhc3QgcGxvdCBmb3JtIHRoZSBwcmV2aW91cyBleGVyY2lzZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGN5bCwgZmlsbCA9IGFtKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikKCiMgMiAtIERlZmluZSBwb3NuX2Qgd2l0aCBwb3NpdGlvbl9kb2RnZSgpCnBvc25fZCA8LSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMikKCiMgMyAtIENoYW5nZSB0aGUgcG9zaXRpb24gYXJndW1lbnQgdG8gcG9zbl9kCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gY3lsLCBmaWxsID0gYW0pKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSBwb3NuX2QpCiMgNCAtIFVzZSBwb3NuX2QgYXMgcG9zaXRpb24gYW5kIGFkanVzdCBhbHBoYSB0byAwLjYKZ2dwbG90KG10Y2FycywgYWVzKHggPSBjeWwsIGZpbGwgPSBhbSkpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9IHBvc25fZCwgYWxwaGEgPSAwLjYpCmBgYAoKT3ZlcmxhcHBpbmcgaGlzdG9ncmFtcwpPdmVybGFwcGluZyBoaXN0b2dyYW1zIHBvc2Ugc2ltaWxhciBwcm9ibGVtcyB0byBvdmVybGFwcGluZyBiYXIgcGxvdHMsIGJ1dCB0aGVyZSBpcyBhIHVuaXF1ZSBzb2x1dGlvbiBoZXJlOiBhIGZyZXF1ZW5jeSBwb2x5Z29uLgoKVGhpcyBpcyBhIGdlb20gc3BlY2lmaWMgdG8gYmlubmVkIGRhdGEgdGhhdCBkcmF3cyBhIGxpbmUgY29ubmVjdGluZyB0aGUgdmFsdWUgb2YgZWFjaCBiaW4uIExpa2UgZ2VvbV9oaXN0b2dyYW0oKSwgaXQgdGFrZXMgYSBiaW53aWR0aCBhcmd1bWVudCBhbmQgYnkgZGVmYXVsdCBzdGF0ID0gImJpbiIgYW5kIHBvc2l0aW9uID0gImlkZW50aXR5Ii4KCmBgYHtyfQojIEEgYmFzaWMgaGlzdG9ncmFtLCBhZGQgY29sb3JpbmcgZGVmaW5lZCBieSBjeWwKZ2dwbG90KG10Y2FycywgYWVzKG1wZywgZmlsbCA9IGN5bCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpCgojIENoYW5nZSBwb3NpdGlvbiB0byBpZGVudGl0eQpnZ3Bsb3QobXRjYXJzLCBhZXMobXBnLCBmaWxsID0gY3lsKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgcG9zaXRpb24gPSAiaWRlbnRpdHkiKQoKCiMgQ2hhbmdlIGdlb20gdG8gZnJlcXBvbHkgKHBvc2l0aW9uIGlzIGlkZW50aXR5IGJ5IGRlZmF1bHQpCmdncGxvdChtdGNhcnMsIGFlcyhtcGcsY29sID0gY3lsKSkgKwogIAogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAxLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpCmBgYAoKQmFyIHBsb3RzIHdpdGggY29sb3IgcmFtcCwgcGFydCAxCkluIHRoaXMgZXhhbXBsZSBvZiBhIGJhciBwbG90LCB5b3UnbGwgZmlsbCBlYWNoIHNlZ21lbnQgYWNjb3JkaW5nIHRvIGFuIG9yZGluYWwgdmFyaWFibGUuIFRoZSBiZXN0IHdheSB0byBkbyB0aGF0IGlzIHdpdGggYSBzZXF1ZW50aWFsIGNvbG9yIHNlcmllcy4KCllvdSdsbCBiZSB1c2luZyB0aGUgVm9jYWIgZGF0YXNldCBmcm9tIGVhcmxpZXIuIFNpbmNlIHRoaXMgaXMgYSBtdWNoIGxhcmdlciBkYXRhc2V0IHdpdGggbW9yZSBjYXRlZ29yaWVzLCB5b3UnbGwgYWxzbyBjb21wYXJlIGl0IHRvIGEgc2ltcGxlciBkYXRhc2V0LCBtdGNhcnMuIEJvdGggZGF0YXNldHMgYXJlIG9yZGluYWwuCgpgYGB7cn0KIyBFeGFtcGxlIG9mIGhvdyB0byB1c2UgYSBicmV3ZWQgY29sb3IgcGFsZXR0ZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGN5bCwgZmlsbCA9IGFtKSkgKwogIGdlb21fYmFyKCkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpCgpgYGAKCk92ZXJsYXBwaW5nIGhpc3RvZ3JhbXMgKDIpCkFzIGEgbGFzdCBleGFtcGxlIG9mIGJhciBwbG90cywgeW91J2xsIHJldHVybiB0byBoaXN0b2dyYW1zICh3aGljaCB5b3Ugbm93IHNlZSBhcmUganVzdCBhIHNwZWNpYWwgdHlwZSBvZiBiYXIgcGxvdCkuIFlvdSBzYXcgYSBuaWNlIHRyaWNrIGluIGEgcHJldmlvdXMgZXhlcmNpc2Ugb2YgaG93IHRvIHNsaWdodGx5IG92ZXJsYXAgYmFycywgYnV0IG5vdyB5b3UnbGwgc2VlIGhvdyB0byBvdmVybGFwIHRoZW0gY29tcGxldGVseS4gVGhpcyB3b3VsZCBiZSBuaWNlIGZvciBtdWx0aXBsZSBoaXN0b2dyYW1zLCBhcyBsb25nIGFzIHRoZXJlIGFyZSBub3QgdG9vIG1hbnkgZGlmZmVyZW50IG92ZXJsYXBzIQoKWW91J2xsIG1ha2UgYSBoaXN0b2dyYW0gdXNpbmcgdGhlIG1wZyB2YXJpYWJsZSBpbiB0aGUgbXRjYXJzIGRhdGEgZnJhbWUuCgpgYGB7cn0KIyAxIC0gQmFzaWMgaGlzdG9ncmFtIHBsb3QgY29tbWFuZApnZ3Bsb3QobXRjYXJzLCBhZXMobXBnKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkKCiMgMiAtIFBsb3QgMSwgRXhwYW5kIGFlc3RoZXRpY3M6IGFtIG9udG8gZmlsbApnZ3Bsb3QobXRjYXJzLCBhZXMobXBnLCBmaWxsID0gYW0pKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKQoKCiMgMyAtIFBsb3QgMiwgY2hhbmdlIHBvc2l0aW9uID0gImRvZGdlIgpnZ3Bsb3QobXRjYXJzLCBhZXMobXBnLCBmaWxsID0gYW0pKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBwb3NpdGlvbiA9ICJkb2RnZSIpCgoKIyA0IC0gUGxvdCAzLCBjaGFuZ2UgcG9zaXRpb24gPSAiZmlsbCIKZ2dwbG90KG10Y2FycywgYWVzKG1wZywgZmlsbCA9IGFtKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgcG9zaXRpb24gPSAiZmlsbCIpCgoKIyA1IC0gUGxvdCA0LCBwbHVzIGNoYW5nZSBwb3NpdGlvbiA9ICJpZGVudGl0eSIgYW5kIGFscGhhID0gMC40CmdncGxvdChtdGNhcnMsIGFlcyhtcGcsIGZpbGwgPSBhbSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIHBvc2l0aW9uID0gImlkZW50aXR5IiwgYWxwaGEgPSAwLjQpCgoKIyA2IC0gUGxvdCA1LCBwbHVzIGNoYW5nZSBtYXBwaW5nOiBjeWwgb250byBmaWxsCmdncGxvdChtdGNhcnMsIGFlcyhtcGcsIGZpbGwgPSBjeWwpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIsIGFscGhhID0gMC40KQpgYGAKCkxpbmUgcGxvdHMKSW4gdGhlIHZpZGVvIHlvdSBzYXcgaG93IHRvIG1ha2UgbGluZSBwbG90cyB1c2luZyB0aW1lIHNlcmllcyBkYXRhLiBUbyBleHBsb3JlIHRoaXMgdG9waWMsIHlvdSdsbCB1c2UgdGhlIGVjb25vbWljcyBkYXRhIGZyYW1lLCB3aGljaCBjb250YWlucyB0aW1lIHNlcmllcyBmb3IgdW5lbXBsb3ltZW50IGFuZCBwb3B1bGF0aW9uIHN0YXRpc3RpY3MgZnJvbSB0aGUgRmVkZXJhbCBSZXNlcnZlIEJhbmsgb2YgU3QuIExvdWlzIGluIHRoZSBVUy4gVGhlIGRhdGEgaXMgY29udGFpbmVkIGluIHRoZSBnZ3Bsb3QyIHBhY2thZ2UuCgpUbyBiZWdpbiB3aXRoLCB5b3UgY2FuIGxvb2sgYXQgaG93IHRoZSBtZWRpYW4gdW5lbXBsb3ltZW50IHRpbWUgYW5kIHRoZSB1bmVtcGxveW1lbnQgcmF0ZSAodGhlIG51bWJlciBvZiB1bmVtcGxveWVkIHBlb3BsZSBhcyBhIHByb3BvcnRpb24gb2YgdGhlIHBvcHVsYXRpb24pIGNoYW5nZSBvdmVyIHRpbWUuCgpJbiB0aGUgbmV4dCBleGVyY2lzZXMsIHlvdSdsbCBleHBsb3JlIHRvIGhvdyBhZGQgZW1iZWxsaXNobWVudHMgdG8gdGhlIGxpbmUgcGxvdHMsIHN1Y2ggYXMgcmVjZXNzaW9uIHBlcmlvZHMuCgpgYGB7cn0KIyBQcmludCBvdXQgaGVhZCBvZiBlY29ub21pY3MKaGVhZChlY29ub21pY3MpCgojIFBsb3QgdW5lbXBsb3kgYXMgYSBmdW5jdGlvbiBvZiBkYXRlIHVzaW5nIGEgbGluZSBwbG90CmdncGxvdChlY29ub21pY3MsIGFlcyh4ID0gZGF0ZSwgeSA9IHVuZW1wbG95KSkgKwogIGdlb21fbGluZSgpCgojIEFkanVzdCBwbG90IHRvIHJlcHJlc2VudCB0aGUgZnJhY3Rpb24gb2YgdG90YWwgcG9wdWxhdGlvbiB0aGF0IGlzIHVuZW1wbG95ZWQKZ2dwbG90KGVjb25vbWljcywgYWVzKHggPSBkYXRlLCB5ID0gdW5lbXBsb3kvcG9wKSkgKwogIGdlb21fbGluZSgpCmBgYAoKUGVyaW9kcyBvZiByZWNlc3Npb24KQnkgdGhlbXNlbHZlcywgdGltZSBzZXJpZXMgb2Z0ZW4gY29udGFpbiBlbm91Z2ggdmFsdWFibGUgaW5mb3JtYXRpb24sIGJ1dCB5b3UgYWx3YXlzIHdhbnQgdG8gbWF4aW1pemUgdGhlIG51bWJlciBvZiB2YXJpYWJsZXMgeW91IGNhbiBzaG93IGluIGEgcGxvdC4gVGhpcyBhbGxvd3MgeW91IChhbmQgeW91ciB2aWV3ZXJzKSB0byBiZWdpbiBtYWtpbmcgY29tcGFyaXNvbnMgYmV0d2VlbiB0aG9zZSB2YXJpYWJsZXMgdGhhdCB3b3VsZCBvdGhlcndpc2UgYmUgZGlmZmljdWx0IG9yIGltcG9zc2libGUuCgpIZXJlLCB5b3UnbGwgYWRkIHNoYWRlZCByZWdpb25zIHRvIHRoZSBiYWNrZ3JvdW5kIHRvIGluZGljYXRlIHJlY2Vzc2lvbiBwZXJpb2RzLiBIb3cgZG8gdW5lbXBsb3ltZW50IHJhdGUgYW5kIHJlY2Vzc2lvbiBwZXJpb2QgaW50ZXJhY3Qgd2l0aCBlYWNoIG90aGVyPwoKSW4gYWRkaXRpb24gdG8gdGhlIGVjb25vbWljcyBkYXRhc2V0IGZyb20gYmVmb3JlLCB5b3UnbGwgYWxzbyB1c2UgdGhlIHJlY2VzcyBkYXRhc2V0IGZvciB0aGUgcGVyaW9kcyBvZiByZWNlc3Npb24uIFRoZSByZWNlc3MgZGF0YSBmcmFtZSBjb250YWlucyAyIHZhcmlhYmxlczogdGhlIGJlZ2luIHBlcmlvZCBvZiB0aGUgcmVjZXNzaW9uIGFuZCB0aGUgZW5kLiBJdCdzIGFscmVhZHkgYXZhaWxhYmxlIGluIHlvdXIgd29ya3NwYWNlLgoKYGBge3J9CiMgQmFzaWMgbGluZSBwbG90CmdncGxvdChlY29ub21pY3MsIGFlcyh4ID0gZGF0ZSwgeSA9IHVuZW1wbG95L3BvcCkpICsKICBnZW9tX2xpbmUoKQoKIyBFeHBhbmQgdGhlIGZvbGxvd2luZyBjb21tYW5kIHdpdGggZ2VvbV9yZWN0KCkgdG8gZHJhdyB0aGUgcmVjZXNzIHBlcmlvZHMKZ2dwbG90KGVjb25vbWljcywgYWVzKHggPSBkYXRlLCB5ID0gdW5lbXBsb3kvcG9wKSkgKwogIGdlb21fcmVjdChkYXRhID0gcmVjZXNzLAogICAgICAgICBhZXMoeG1pbiA9IGJlZ2luLCB4bWF4ID0gZW5kLCB5bWluID0gLUluZiwgeW1heCA9ICtJbmYpLAogICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCBmaWxsID0gInJlZCIsIGFscGhhID0gMC4yKSArCiAgZ2VvbV9saW5lKCkKYGBgCgpNdWx0aXBsZSB0aW1lIHNlcmllcywgcGFydCAxCkluIHRoZSBkYXRhIGNoYXB0ZXIgd2UgZGlzY3Vzc2VkIGhvdyB0aGUgZm9ybSBvZiB5b3VyIGRhdGEgYWZmZWN0cyBob3cgeW91IGNhbiBwbG90IGl0LiBIZXJlLCB5b3UnbGwgZXhwbG9yZSB0aGF0IHRvcGljIGluIHRoZSBjb250ZXh0IG9mIG11bHRpcGxlIHRpbWUgc2VyaWVzLgoKVGhlIGRhdGFzZXQgeW91J2xsIHVzZSBjb250YWlucyB0aGUgZ2xvYmFsIGNhcHR1cmUgcmF0ZXMgb2Ygc2V2ZW4gc2FsbW9uIHNwZWNpZXMgZnJvbSAxOTUwIC0gMjAxMC4KCkluIHlvdXIgd29ya3NwYWNlLCB0aGUgZm9sbG93aW5nIGRhdGFzZXQgaXMgYXZhaWxhYmxlOgoKZmlzaC5zcGVjaWVzOiBFYWNoIHZhcmlhYmxlIChjb2x1bW4pIGlzIGEgU2FsbW9uIFNwZWNpZXMgYW5kIGVhY2ggb2JzZXJ2YXRpb24gKHJvdykgaXMgb25lIFllYXIuClRvIGdldCBhIG11bHRpcGxlIHRpbWUgc2VyaWVzIHBsb3QsIGhvd2V2ZXIsIGJvdGggWWVhciBhbmQgU3BlY2llcyBzaG91bGQgYmUgaW4gdGhlaXIgb3duIGNvbHVtbi4gWW91IG5lZWQgdGlkeSBkYXRhOiBvbmUgdmFyaWFibGUgcGVyIGNvbHVtbi4gT25jZSB5b3UgaGF2ZSB0aGF0IHlvdSBjYW4gZ2V0IHRoZSBwbG90IHNob3duIGluIHRoZSB2aWV3ZXIgYnkgbWFwcGluZyBZZWFyIHRvIHRoZSB4IGFlc3RoZXRpYyBhbmQgU3BlY2llcyB0byB0aGUgY29sb3IgYWVzdGhldGljLgoKWW91J2xsIHVzZSB0aGUgZ2F0aGVyKCkgZnVuY3Rpb24gb2YgdGhlIHRpZHlyIHBhY2thZ2UsIHdoaWNoIGlzIGFscmVhZHkgbG9hZGVkIGZvciB5b3UuCgpgYGB7cn0KIyBDaGVjayB0aGUgc3RydWN0dXJlIGFzIGEgc3RhcnRpbmcgcG9pbnQKc3RyKGZpc2guc3BlY2llcykKCiMgVXNlIGdhdGhlciB0byBnbyBmcm9tIGZpc2guc3BlY2llcyB0byBmaXNoLnRpZHkKZmlzaC50aWR5IDwtIGdhdGhlcihmaXNoLnNwZWNpZXMsIFNwZWNpZXMsIENhcHR1cmUsIC1ZZWFyKQpgYGAKCk11bHRpcGxlIHRpbWUgc2VyaWVzLCBwYXJ0IDIKTm93IHRoYXQgeW91IGhhdmUgdGlkeSBkYXRhLCB5b3UncmUgcmVhZHkgdG8gbWFrZSB5b3VyIHBsb3QhIFRoZSBkYXRhIGZyYW1lIGZpc2gudGlkeSBpcyBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgd29ya3NwYWNlLCBzbyB5b3UgY2FuIHN0YXJ0IHJpZ2h0IGF3YXkhCgpgYGB7cn0KIyBSZWNyZWF0ZSB0aGUgcGxvdCBzaG93biBvbiB0aGUgcmlnaHQKZ2dwbG90KGZpc2gudGlkeSwgYWVzKHggPSBZZWFyLCB5ID0gQ2FwdHVyZSwgY29sb3IgPSBTcGVjaWVzKSkgKyBnZW9tX2xpbmUoKQoKYGBgCgpVc2luZyBxcGxvdApGb3Igc2ltcGxlIGV4cGxvcmF0b3J5IHBsb3RzLCB0aGVyZSBhcmUgYSB2YXJpZXR5IG9mIGZ1bmN0aW9ucyBhdmFpbGFibGUuIGdncGxvdDIgb2ZmZXJzIGEgcG93ZXJmdWwgYW5kIGRpdmVyc2UgYXJyYXkgb2YgZnVuY3Rpb25zLCBidXQgcXBsb3QoKSBhbGxvd3MgZm9yIHF1aWNrIGFuZCBkaXJ0eSBwbG90cy4gUGx1cywgeW91IHNob3VsZCBhbHNvIGJlIGZhbWlsaWFyIHdpdGggYmFzaWMgcGxvdHRpbmcgbm90YXRpb24uCgpgYGB7cn0KIyBUaGUgb2xkIHdheSAoc2hvd24pCnBsb3QobXBnIH4gd3QsIGRhdGEgPSBtdGNhcnMpICMgZm9ybXVsYSBub3RhdGlvbgp3aXRoKG10Y2FycywgcGxvdCh3dCwgbXBnKSkgIyB4LCB5IG5vdGF0aW9uCgojIFVzaW5nIGdncGxvdDoKZ2dwbG90KG10Y2FycywgYWVzKHggPSB3dCwgeSA9IG1wZykpICsKICBnZW9tX3BvaW50KCkKCiMgVXNpbmcgcXBsb3Q6CnFwbG90KHd0LCBtcGcsIGRhdGEgPSBtdGNhcnMpCmBgYAoKVXNpbmcgYWVzdGhldGljcwpZb3UgYWxyZWFkeSBzYXcgaG93IHNvbWUgYWVzdGhldGljcyBhcmUgb25seSBhcHBsaWNhYmxlIHRvIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgc3VjaCBhcyBzaGFwZXMgYW5kIGxpbmV0eXBlcy4gQnV0IGp1c3QgYmVjYXVzZSBvdGhlcnMsIHN1Y2ggYXMgc2l6ZSBhbmQgY29sb3IgKGFuZCBoZW5jZSBmaWxsKSwgY2FuIGJlIGFwcGxpZWQgdG8gYm90aCBjYXRlZ29yaWNhbCBhbmQgY29udGludW91cyB2YXJpYWJsZXMsIGRvZXNuJ3QgbWVhbiB0aGF0IHRoZXkncmUgc3VpdGFibGUgZm9yIGJvdGguCgpgYGB7cn0KIyBiYXNpYyBzY2F0dGVyIHBsb3Q6CnFwbG90KHd0LCBtcGcsIGRhdGEgPSBtdGNhcnMpCgojIENhdGVnb3JpY2FsOgojIGN5bApxcGxvdCh3dCwgbXBnLCBkYXRhID0gbXRjYXJzLCBzaXplID0gZmFjdG9yKGN5bCkpCgojIGdlYXIKcXBsb3Qod3QsIG1wZywgZGF0YSA9IG10Y2Fycywgc2l6ZSA9IGZhY3RvcihnZWFyKSkKCiMgQ29udGludW91cwojIGhwCnFwbG90KHd0LCBtcGcsIGRhdGEgPSBtdGNhcnMsIGNvbG9yID0gaHApCgojIHFzZWMKcXBsb3Qod3QsIG1wZywgZGF0YSA9IG10Y2FycywgY29sb3IgPSBxc2VjKQpgYGAKCkNob29zaW5nIGdlb21zLCBwYXJ0IDEKcXBsb3QgYXV0b21hdGljYWxseSB0YWtlcyBjYXJlIG9mIGFzc2lnbmluZyBhIGdlb20gdG8gb3VyIHBsb3QgZ2l2ZW4gdGhlIHR5cGUgb2YgZGF0YSwgYnV0IHlvdSBjYW4gc3BlY2lmeSB0aGUgZ2VvbSB5b3Vyc2VsdmVzLgoKYGBge3J9CiMgcXBsb3QoKSB3aXRoIHggb25seQpxcGxvdCh4ID0gZmFjdG9yKGN5bCksIGRhdGEgPSBtdGNhcnMpCgojIHFwbG90KCkgd2l0aCB4IGFuZCB5CnFwbG90KHggPSBmYWN0b3IoY3lsKSwgeSA9IGZhY3Rvcih2cyksIGRhdGEgPSBtdGNhcnMpCgojIHFwbG90KCkgd2l0aCBnZW9tIHNldCB0byBqaXR0ZXIgbWFudWFsbHkKcXBsb3QoeCA9IGZhY3RvcihjeWwpLCB5ID0gZmFjdG9yKHZzKSwgZGF0YSA9IG10Y2FycywgZ2VvbSA9ICJqaXR0ZXIiKQoKYGBgCgpDaG9vc2luZyBnZW9tcywgcGFydCAyIC0gZG90cGxvdApTb21lIG5hbWluZyBjb252ZW50aW9uczoKClNjYXR0ZXIgcGxvdHM6CkNvbnRpbnVvdXMgeCwgY29udGludW91cyB5LgpEb3QgcGxvdHM6CkNhdGVnb3JpY2FsIHgsIGNvbnRpbnVvdXMgeS4KWW91IHVzZSBnZW9tX3BvaW50KCkgZm9yIGJvdGggcGxvdCB0eXBlcy4gSml0dGVyaW5nIHBvc2l0aW9uIGlzIHNldCBpbiB0aGUgZ2VvbV9wb2ludCgpIGxheWVyLgoKSG93ZXZlciwgdG8gbWFrZSBhICJ0cnVlIiBkb3QgcGxvdCwgeW91IGNhbiB1c2UgZ2VvbV9kb3RwbG90KCkuIFRoZSBkaWZmZXJlbmNlIGlzIHRoYXQgdW5saWtlIGdlb21fcG9pbnQoKSwgZ2VvbV9kb3RwbG90KCkgdXNlcyBhIGJpbm5pbmcgc3RhdGlzdGljLiBCaW5uaW5nIG1lYW5zIHRvIGN1dCB1cCBhIGNvbnRpbnVvdXMgdmFyaWFibGUgKHRoZSB5IGluIHRoaXMgY2FzZSkgaW50byBkaXNjcmV0ZSAiYmlucyIuIFlvdSBhbHJlYWR5IHNhdyBiaW5uaW5nIHdpdGggZ2VvbV9oaXN0b2dyYW0oKSAoc2VlIHRoaXMgZXhlcmNpc2UgZm9yIGEgcmVmcmVzaGVyKS4KCk9uZSB0aGluZyB0byBub3RpY2UgaXMgdGhhdCBnZW9tX2RvdHBsb3QoKSB1c2VzIGEgZGlmZmVyZW50IHBsb3R0aW5nIHN5bWJvbCB0byBnZW9tX3BvaW50KCkuIEZvciB0aGVzZSBzeW1ib2xzLCB0aGUgY29sb3IgYWVzdGhldGljIGNoYW5nZXMgdGhlIGNvbG9yIG9mIGl0cyBib3JkZXIsIGFuZCB0aGUgZmlsbCBhZXN0aGV0aWMgY2hhbmdlcyB0aGUgY29sb3Igb2YgaXRzIGludGVyaW9yLgoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgaG93IHRoZSB0d28gZ2VvbXMgY29tcGFyZS4KCmBgYHtyfQojIGN5bCBhbmQgYW0gYXJlIGZhY3RvcnMsIHd0IGlzIG51bWVyaWMKY2xhc3MobXRjYXJzJGN5bCkKY2xhc3MobXRjYXJzJGFtKQpjbGFzcyhtdGNhcnMkd3QpCgojICJCYXNpYyIgZG90IHBsb3QsIHdpdGggZ2VvbV9wb2ludCgpOgpnZ3Bsb3QobXRjYXJzLCBhZXMoY3lsLCB3dCwgY29sID0gYW0pKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcigwLjIsIDApKQoKIyAxIC0gIlRydWUiIGRvdCBwbG90LCB3aXRoIGdlb21fZG90cGxvdCgpOgpnZ3Bsb3QobXRjYXJzLCBhZXMoY3lsLCB3dCwgZmlsbCA9IGFtKSkgKwogIGdlb21fZG90cGxvdChiaW5heGlzID0gInkiLCBzdGFja2RpciA9ICJjZW50ZXIiKQoKIyAyIC0gcXBsb3Qgd2l0aCBnZW9tICJkb3RwbG90IiwgYmluYXhpcyA9ICJ5IiBhbmQgc3RhY2tkaXIgPSAiY2VudGVyIgpxcGxvdCgKICBjeWwsIHd0LAogIGRhdGEgPSBtdGNhcnMsCiAgZmlsbCA9IGFtLAogIGdlb20gPSAiZG90cGxvdCIsCiAgYmluYXhpcyA9ICJ5IiwKICBzdGFja2RpciA9ICJjZW50ZXIiCikKYGBgCgpDaGlja2VuIHdlaWdodApUaGUgQ2hpY2tXZWlnaHQgZGF0YXNldCBpcyBhIGRhdGEgZnJhbWUgd2hpY2ggcmVwcmVzZW50cyB0aGUgcHJvZ3Jlc3Npb24gb2Ygd2VpZ2h0IG9mIHNldmVyYWwgY2hpY2tzLiBUaGUgbGl0dGxlIGNoaWNrbGluZ3MgYXJlIGVhY2ggZ2l2ZW4gYSBzcGVjaWZpYyBkaWV0LiBUaGVyZSBhcmUgZm91ciB0eXBlcyBvZiBkaWV0IGFuZCB0aGUgZmFybWVyIHdhbnRzIHRvIGtub3cgd2hpY2ggb25lIGZhdHRlbnMgdGhlIGNoaWNrcyB0aGUgZmFzdGVzdC4KCkl0J3MgdGltZSB0byBkbyBzb21lIGV4cGxvcmF0b3J5IHN0YXRpc3RpY3Mgb24gdGhlIGRhdGEgZnJhbWUgdXNpbmcgdGhlIHRlY2huaXF1ZXMgeW91IGxlYXJuZWQgaW4gdGhpcyBjb3Vyc2UhIExldCdzIGRvIHNvbWUgZ2dwbG90LWluZyEKCmBgYHtyfQojIENoaWNrV2VpZ2h0IGlzIGF2YWlsYWJsZSBpbiB5b3VyIHdvcmtzcGFjZQojIDEgLSBDaGVjayBvdXQgdGhlIGhlYWQgb2YgQ2hpY2tXZWlnaHQKaGVhZChDaGlja1dlaWdodCkKCiMgMiAtIEJhc2ljIGxpbmUgcGxvdApnZ3Bsb3QoQ2hpY2tXZWlnaHQsIGFlcyh4ID0gVGltZSwgeSA9IHdlaWdodCkpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gQ2hpY2spKQoKIyAzIC0gVGFrZSBwbG90IDIsIG1hcCBEaWV0IG9udG8gY29sLgpnZ3Bsb3QoQ2hpY2tXZWlnaHQsIGFlcyh4ID0gVGltZSwgeSA9IHdlaWdodCwgY29sb3IgPSBEaWV0KSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBDaGljaykpCgojIDQgLSBUYWtlIHBsb3QgMywgYWRkIGdlb21fc21vb3RoKCkKZ2dwbG90KENoaWNrV2VpZ2h0LCBhZXMoeCA9IFRpbWUsIHkgPSB3ZWlnaHQsIGNvbG9yID0gRGlldCkpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gQ2hpY2spLCBhbHBoYSA9IDAuMykgKwogIGdlb21fc21vb3RoKGx3ZCA9IDIsIHNlID0gRkFMU0UpCmBgYAo=